aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rwxr-xr-xutils/DSAclean.py32
-rw-r--r--utils/DSAextract.py111
-rwxr-xr-xutils/GenLibDeps.pl241
-rw-r--r--utils/Makefile21
-rw-r--r--utils/NLT.schema8
-rwxr-xr-xutils/NewNightlyTest.pl1179
-rw-r--r--utils/NightlyTest.gnuplot214
-rw-r--r--utils/NightlyTestTemplate.html244
-rw-r--r--utils/OldenDataRecover.pl37
-rw-r--r--utils/PerfectShuffle/Makefile18
-rw-r--r--utils/PerfectShuffle/PerfectShuffle.cpp497
-rwxr-xr-xutils/RegressionFinder.pl186
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp741
-rw-r--r--utils/TableGen/AsmWriterEmitter.h50
-rw-r--r--utils/TableGen/CMakeLists.txt32
-rw-r--r--utils/TableGen/CallingConvEmitter.cpp206
-rw-r--r--utils/TableGen/CallingConvEmitter.h38
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp169
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.h46
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp251
-rw-r--r--utils/TableGen/CodeEmitterGen.h43
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp2395
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h597
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp273
-rw-r--r--utils/TableGen/CodeGenInstruction.h153
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h87
-rw-r--r--utils/TableGen/CodeGenRegisters.h61
-rw-r--r--utils/TableGen/CodeGenTarget.cpp576
-rw-r--r--utils/TableGen/CodeGenTarget.h243
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp2131
-rw-r--r--utils/TableGen/DAGISelEmitter.h56
-rw-r--r--utils/TableGen/FastISelEmitter.cpp636
-rw-r--r--utils/TableGen/FastISelEmitter.h39
-rw-r--r--utils/TableGen/InstrEnumEmitter.cpp55
-rw-r--r--utils/TableGen/InstrEnumEmitter.h33
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp381
-rw-r--r--utils/TableGen/InstrInfoEmitter.h68
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp716
-rw-r--r--utils/TableGen/IntrinsicEmitter.h60
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.cpp2131
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.h33
-rw-r--r--utils/TableGen/Makefile20
-rw-r--r--utils/TableGen/Record.cpp1485
-rw-r--r--utils/TableGen/Record.h1444
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp907
-rw-r--r--utils/TableGen/RegisterInfoEmitter.h40
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp513
-rw-r--r--utils/TableGen/SubtargetEmitter.h62
-rw-r--r--utils/TableGen/TGLexer.cpp460
-rw-r--r--utils/TableGen/TGLexer.h129
-rw-r--r--utils/TableGen/TGParser.cpp1937
-rw-r--r--utils/TableGen/TGParser.h115
-rw-r--r--utils/TableGen/TGSourceMgr.cpp105
-rw-r--r--utils/TableGen/TGSourceMgr.h106
-rw-r--r--utils/TableGen/TGValueTypes.cpp126
-rw-r--r--utils/TableGen/TableGen.cpp270
-rw-r--r--utils/TableGen/TableGenBackend.cpp25
-rw-r--r--utils/TableGen/TableGenBackend.h43
-rw-r--r--utils/buildit/GNUmakefile115
-rwxr-xr-xutils/buildit/build_llvm272
-rwxr-xr-xutils/cgiplotNLT.pl68
-rwxr-xr-xutils/check-each-file150
-rwxr-xr-xutils/codegen-diff135
-rwxr-xr-xutils/countloc.sh40
-rw-r--r--utils/emacs/README27
-rw-r--r--utils/emacs/emacs.el36
-rw-r--r--utils/emacs/llvm-mode.el128
-rw-r--r--utils/emacs/tablegen-mode.el122
-rwxr-xr-xutils/findmisopt178
-rwxr-xr-xutils/findoptdiff101
-rwxr-xr-xutils/findsym.pl33
-rw-r--r--utils/fpcmp/Makefile16
-rw-r--r--utils/fpcmp/fpcmp.cpp43
-rwxr-xr-xutils/getsrcs.sh34
-rw-r--r--utils/importNLT.pl86
-rw-r--r--utils/jedit/README14
-rw-r--r--utils/jedit/tablegen.xml39
-rw-r--r--utils/lint/common_lint.py97
-rwxr-xr-xutils/lint/cpp_lint.py94
-rwxr-xr-xutils/lint/generic_lint.py24
-rwxr-xr-xutils/lint/remove_trailing_whitespace.sh6
-rwxr-xr-xutils/llvm-native-gcc249
-rwxr-xr-xutils/llvm-native-gxx249
-rw-r--r--utils/llvm.grm409
-rwxr-xr-xutils/llvmdo188
-rwxr-xr-xutils/llvmgrep39
-rwxr-xr-xutils/makellvm145
-rwxr-xr-xutils/mkpatch37
-rw-r--r--utils/parseNLT.pl34
-rw-r--r--utils/plotNLT.pl53
-rwxr-xr-xutils/profile.pl74
-rw-r--r--utils/unittest/Makefile13
-rw-r--r--utils/unittest/googletest/LICENSE.TXT28
-rw-r--r--utils/unittest/googletest/Makefile27
-rw-r--r--utils/unittest/googletest/README.LLVM26
-rw-r--r--utils/unittest/googletest/gtest-death-test.cc775
-rw-r--r--utils/unittest/googletest/gtest-filepath.cc321
-rw-r--r--utils/unittest/googletest/gtest-port.cc332
-rw-r--r--utils/unittest/googletest/gtest-test-part.cc124
-rw-r--r--utils/unittest/googletest/gtest-typed-test.cc97
-rw-r--r--utils/unittest/googletest/gtest.cc3951
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-death-test.h209
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-message.h224
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-param-test.h1385
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-spi.h221
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-test-part.h179
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-typed-test.h253
-rw-r--r--utils/unittest/googletest/include/gtest/gtest.h1317
-rw-r--r--utils/unittest/googletest/include/gtest/gtest_pred_impl.h368
-rw-r--r--utils/unittest/googletest/include/gtest/gtest_prod.h58
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h201
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-filepath.h192
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h1267
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-internal.h876
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h242
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h4572
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-param-util.h629
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-port.h862
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-string.h335
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-type-util.h3319
-rwxr-xr-xutils/userloc.pl216
-rw-r--r--utils/vim/README43
-rw-r--r--utils/vim/llvm.vim104
-rw-r--r--utils/vim/tablegen.vim54
-rw-r--r--utils/vim/vimrc72
-rwxr-xr-xutils/webNLT.pl83
126 files changed, 49185 insertions, 0 deletions
diff --git a/utils/DSAclean.py b/utils/DSAclean.py
new file mode 100755
index 000000000000..6c43357019ef
--- /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 000000000000..134e9453fbb5
--- /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 000000000000..73f3e71491a7
--- /dev/null
+++ b/utils/GenLibDeps.pl
@@ -0,0 +1,241 @@
+#!/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]
+#
+use strict;
+
+# 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;
+my @libs = grep(/libLLVM.*\.(dylib|so|a)$/,sort(@files));
+my @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 my $lib (@libs ) {
+ open DEFS, "$nmPath -g $Directory/$lib|";
+ while (<DEFS>) {
+ next if (! / [ABCDGRST] /);
+ s/^[^ ]* [ABCDGRST] //;
+ s/\015?\012//; # not sure if <DEFS> is in binmode and uses LF or CRLF.
+ # this strips both LF and CRLF.
+ $libdefs{$_} = $lib;
+ }
+ close DEFS or die "nm failed";
+}
+
+# Gather definitions from the object files.
+foreach my $obj (@objs ) {
+ open DEFS, "$nmPath -g $Directory/$obj |";
+ while (<DEFS>) {
+ next if (! / [ABCDGRST] /);
+ s/^[^ ]* [ABCDGRST] //;
+ s/\015?\012//; # not sure if <DEFS> is in binmode and uses LF or CRLF.
+ # this strips both LF and CRLF.
+ $objdefs{$_} = $obj;
+ }
+ close DEFS or die "nm failed";
+}
+
+# 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/^[ 0]* 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) {
+ my $libroot = $lib;
+ $libroot =~ s/lib(.*).a/$1/;
+ if ($objdefs{$_} ne "$libroot.o") {
+ $DepLibs{$objdefs{$_}} = [] unless exists $DepLibs{$objdefs{$_}};
+ push(@{$DepLibs{$objdefs{$_}}}, $_);
+ }
+ }
+ }
+ close UNDEFS or die "nm failed";
+ unless(keys %DepLibs) {
+ # above failed
+ open UNDEFS, "$nmPath -g -u $Directory/$lib |";
+ while (<UNDEFS>) {
+ # to bypass non-working sed
+ if (' ' eq substr($_,0,2) and index($_,'U ')) {
+ $_ = substr($_,index($_,'U ')+2)
+ };
+ $_ = substr($_,index($_,' *U ')+5) if -1!=index($_,' *U ');
+
+ 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) {
+ my $libroot = $lib;
+ $libroot =~ s/lib(.*).a/$1/;
+ if ($objdefs{$_} ne "$libroot.o") {
+ $DepLibs{$objdefs{$_}} = [] unless exists $DepLibs{$objdefs{$_}};
+ push(@{$DepLibs{$objdefs{$_}}}, $_);
+ }
+ }
+ }
+ close UNDEFS or die "nm failed";
+ }
+
+ for my $key (sort keys %DepLibs) {
+ if ($FLAT) {
+ print " $key";
+ if ($WHY) {
+ print "\n";
+ my @syms = @{$DepLibs{$key}};
+ foreach my $sym (@syms) {
+ print " $sym\n";
+ }
+ }
+ } else {
+ print " <li>$key</li>\n";
+ }
+ my $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 my $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 my $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 000000000000..c43086ba21dc
--- /dev/null
+++ b/utils/Makefile
@@ -0,0 +1,21 @@
+##===- utils/Makefile --------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ..
+PARALLEL_DIRS := TableGen fpcmp PerfectShuffle unittest
+
+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 000000000000..4bcddbc9f7f6
--- /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 000000000000..9672632fa273
--- /dev/null
+++ b/utils/NewNightlyTest.pl
@@ -0,0 +1,1179 @@
+#!/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 parallel jobs with GNU Make (see -parallel-jobs).
+# -parallel-jobs The number of parallel Make jobs to use (default is two).
+# -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.
+# -disable-lto Disable link time optimization.
+# -disable-bindings Disable building LLVM bindings.
+# -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.
+# -submit-aux If specified, an auxiliary script to run in addition to the
+# normal submit script. The script will be passed the path to
+# the "sentdata.txt" file as its sole argument.
+# -nosubmit Do not report the test results back to a submit server.
+#
+# 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";
+$SUBMITAUX="";
+$SUBMIT = 1;
+$PARALLELJOBS = "2";
+
+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-jobs$/) { $PARALLELJOBS = "$ARGV[0]"; shift; next;}
+ if (/^-parallel$/) { $MAKEOPTS = "$MAKEOPTS -j$PARALLELJOBS -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-bindings$/) { $CONFIGUREARGS .= " --disable-bindings"; next; }
+ if (/^-disable-cbe$/) { $PROGTESTOPTS .= " DISABLE_CBE=1"; next; }
+ if (/^-disable-lto$/) { $PROGTESTOPTS .= " DISABLE_LTO=1"; next; }
+ if (/^-test-opts$/) { $PROGTESTOPTS .= " $ARGV[0]"; shift; 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 (/^-submit-aux/) { $SUBMITAUX = "$ARGV[0]"; shift; next; }
+ if (/^-nosubmit$/) { $SUBMIT = 0; 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'} . '/bin';
+}
+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];
+
+ # Write out the "...-sentdata.txt" file.
+
+ my $sentdata="";
+ foreach $x (keys (%$variables)){
+ $value = $variables->{$x};
+ $sentdata.= "$x => $value\n";
+ }
+ WriteFile "$Prefix-sentdata.txt", $sentdata;
+
+ if (!($SUBMITAUX eq "")) {
+ system "$SUBMITAUX \"$Prefix-sentdata.txt\"";
+ }
+
+ # Create the content to send to the server.
+
+ my $content;
+ foreach $key (keys (%$variables)){
+ $value = $variables->{$key};
+ $value =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
+ $content .= "$key=$value&";
+ }
+
+ # Send the data to the server.
+ #
+ # FIXME: This code should be more robust?
+
+ $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]);
+
+ $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);
+
+ 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";
+}
+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
+);
+
+if ($SUBMIT) {
+ my $response = SendData $SUBMITSERVER,$SUBMITSCRIPT,\%hash_of_data;
+ if( $VERBOSE) { print "============================\n$response"; }
+} else {
+ print "============================\n";
+ foreach $x(keys %hash_of_data){
+ print "$x => $hash_of_data{$x}\n";
+ }
+}
+
+##############################################################
+#
+# 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 000000000000..514b72ab20ad
--- /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 000000000000..c38bb2e776bb
--- /dev/null
+++ b/utils/NightlyTestTemplate.html
@@ -0,0 +1,244 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>LLVM Test Results for $DateString</title></head>
+
+<body bgcolor=white>
+<center><font size=+3 face=Verdana><b>LLVM Test Results for $DateString</b></font></center>
+<hr height=1>
+
+<table width=100%>
+<tr><td valign=top align=center>
+
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="5" cellspacing="0"><tr><td bgcolor="#DDAA77">
+<font size=+1><b>Sections:</b></font><br>
+</td></tr><tr><td bgcolor="#FFCC99" align=center>
+<a href="#Overview">Overview</a><br>
+<a href="#Changes">Changes</a><br>
+<a href="#Dejagnu">Dejagnu Tests</a><br>
+<a href="#Trends">Trends</a><br>
+<a href="#Programs">Programs</a><br>
+</td></tr></table></td></tr></table>
+
+<p>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="5" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+1><b>Previous:</b></font><br>
+</td></tr><tr><td bgcolor="#FFCC99">
+ $PrevDaysList
+</td></tr></table></td></tr></table>
+<p>
+
+<font size=+1><b>Back to:</b></font><br>
+<a href="http://llvm.org/testresults/">Test&nbsp;Results</a><br>
+<a href="http://llvm.org/">LLVM&nbsp;Page</a><p>
+
+</td><td valign=top>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Overview">Today's Test Results Overview</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+<!-- Running LOC graph -->
+<table align=right>
+<tr><td>
+<a href="running_loc_large.png"
+ ><img border=0 width=480 height=360 src="running_loc.png"></a>
+</td></tr>
+<tr><td align=center>Lines Of Code over Time<br>
+<font size=-1><a href="running_loc_large.png">Click for larger view</a></font>
+</td></tr>
+</table>
+
+<h2>Nightly Test Overview:</h2>
+<ul>
+ <li>Start: <b>$TestStartTime</b></li>
+ <li>Finish: <b>$TestFinishTime</b></li>
+ <li>Platform: <b>$TestPlatform</b></li>
+</ul>
+<h2>CVS Tree Overview:</h2>
+<ul>
+<li><a href="$DATE-CVS-Log.txt">CVS Checkout Log</a>
+<ul>
+ <b>$NumDirsInCVS</b> dirs, <b>$NumFilesInCVS</b> files, <b>$LOC</b>
+ lines of code, checked out in <b>$CVSCheckoutTime</b> seconds<br></ul>
+<li><a href="$DATE-Build-Log.txt">Compilation Log</a>
+<table>
+<tr><td><b>Item</b></td><td><b>CPU Time</b></td><td><b>Wall Clock</b></td></tr>
+<tr><td>Configure CVS Tree</td><td>$ConfigTime</td><td>$ConfigWallTime</td></tr>
+<tr><td>Build CVS Tree</td><td>$BuildTime</td><td>$BuildWallTime</td></tr>
+<tr><td>Run Dejagnu Tests</td><td>$DejagnuTime</td><td>$DejagnuWallTime</td></tr>
+</table></li>
+<li>Number of object files compiled: <b>$NumObjects</b></li>
+<li>Number of libraries linked: <b>$NumLibraries</b></li>
+<li>Number of executables linked:<b> $NumExecutables</b></li>
+<li>Build Status: $BuildStatus</li>
+</ul>
+
+<h2>Warnings during the build:</h2>
+$WarningsList
+
+<br><br><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Changes">Changes from Yesterday</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+<h2>Changes to CVS:</h2>
+<ul>
+<li>Users who committed to CVS: <b>$UserCommitList</b>
+<li>Users who updated from CVS: <b>$UserUpdateList</b>
+<li>Added Files: $AddedFilesList
+<li>Modified Files: $ModifiedFilesList
+<li>Removed Files: $RemovedFilesList
+</ul><p>
+
+<h2>Changes to Warnings:</h2>
+<p>Warnings Added:</p>
+$WarningsAdded
+<p>Warnings Removed:</p>
+$WarningsRemoved
+
+<h2>Changes in the test suite:</h2>
+<ul>
+<li>New Tests: $TestsAdded
+<li>Removed Tests: $TestsRemoved
+<li>Newly passing tests: $TestsFixed
+<li>Newly failing tests: $TestsBroken
+</ul>
+</td></tr></tbody></table>
+
+
+<br/><br/><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Dejagnu">Dejagnu Test Results</font></b>
+</td></tr></table></td></tr></table></center>
+<br/>
+$DejagnuTestResults
+<p>A complete log of testing <a href="$DATE-Dejagnu-testrun.log">Feature and Regression</a> is available for further analysis.</p>
+
+<br><br><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Trends">Changes Over Time</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+
+Here are some charts showing how the LLVM optimizer and code generators are
+changing over time. For now we use the Olden benchmark suite to measure this,
+but eventually we will switch to using SPEC CPU2000. All programs are run with
+"LARGE_PROBLEM_SIZE" enabled. Click on any of the charts to get a larger
+version.<p>
+
+<h2>Compilation Measurements:</h2>
+
+<table border="0" align=center>
+<tr>
+<td width=50% align=center>
+<a href="running_Olden_bytecode_large.png"><img width=480 height=360 border=0 src="running_Olden_bytecode.png"></a><br>
+Size of LLVM bytecode files
+</td>
+<td width=50% align=center>
+<a href="running_Olden_opt_time_large.png"><img width=480 height=360 border=0 src="running_Olden_opt_time.png"></a><br>
+Time to run the LLVM optimizer on each program
+</td></tr>
+</table>
+
+<h2>Program Execution Measurements:</h2>
+
+<table border="0" align=center>
+<tr>
+<td width=50% align=center>
+<a href="running_Olden_cbe_time_large.png"><img width=480 height=360 border=0 src="running_Olden_cbe_time.png"></a><br>
+Execution time for CBE generated executable
+</td>
+<td width=50% align=center>
+<a href="running_Olden_llc_time_large.png"><img width=480 height=360 border=0 src="running_Olden_llc_time.png"></a><br>
+Execution time for the LLC generated executable
+</td></tr>
+
+<tr>
+<td align=center>
+<a href="running_Olden_jit_time_large.png"><img width=480 height=360 border=0 src="running_Olden_jit_time.png"></a><br>
+Execution time for program in the JIT
+</td>
+<td></td></tr>
+</table>
+
+
+
+
+<br><br><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Programs">Program Tests</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+This section tests LLVM on a variety of programs in the test suite. This
+includes benchmark suites like the Olden, McCat, Ptrdist, and SPEC benchmarks as
+well as a few random programs with test inputs. This section is meant to track
+how stable LLVM is as a whole. A failure in the execution of any test is marked
+with an asterisk: `*'. The columns of the tables are:<p>
+
+<ol>
+<li><a name="Program">Program</a> - The name of the program for that row.</li>
+<li><a name="GCCAS">GCCAS</a> - Time to run LLVM optimizers on the program.</li>
+<li><a name="Bytecode">Bytecode</a> - The size of the bytecode for the
+ program</li>
+<li><a name="Instrs">Instrs</a> - The number of LLVM instructions in the
+ compiled bytecode</li>
+<li><a name="LLC<br>compile">LLC compile</a> - The time taken compile with
+ LLC (the static backend)</li>
+<li><a name="JIT<br>codegen">JIT codegen</a> - The amount of time spent in the
+ JIT itself, instead of executing the program.</li>
+<li><a name="Machine<br>code">Machine code</a> - The number of bytes of machine
+ code generated by the JIT.</li>
+<li><a name="GCC">GCC</a> - The time taken to execute the program when compiled
+ with GCC -O2.</li>
+<li><a name="CBE">CBE</a> - The time taken to execute the program after
+ compilation through the C backend, compiled with -O2.</li>
+<li><a name="LLC">LLC</a> - How long does the program generated by the static
+ backend LLC take to execute </li>
+<li><a name="JIT">JIT</a> - The amount of time spent running the
+ program with the JIT; this includes the code generation phase (listed above)
+ and actually running the program.</li>
+<li><a name="GCC/LLC">GCC/LLC</a> - The speed-up of the LLC output vs the native
+ GCC output: greater than 1 is a speedup, less than 1 is a slowdown.</li>
+<li><a name="GCC/CBE">GCC/CBE</a> - The speed-up of the CBE output vs the native
+ GCC output: greater than 1 is a speedup, less than 1 is a slowdown.</li>
+<li><a name="LLC-BETA">LLC-BETA</a> - How long does the program generated by the static
+ backend LLC take to execute the program, when compiled with new experimental
+ features. This is temporary, for tuning.</li>
+</ol><p>
+
+A complete log of testing
+<a href="$DATE-SingleSource-ProgramTest.txt.gz">SingleSource</a>,
+<a href="$DATE-MultiSource-ProgramTest.txt.gz">MultiSource</a>, and
+<a href="$DATE-External-ProgramTest.txt.gz">External</a> programs are
+available for further analysis.
+
+<h2>Programs/External</h2>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+$ExternalProgramsTable
+</td></tr></table></center>
+
+<h2>Programs/MultiSource</h2>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+$MultiSourceProgramsTable
+</td></tr></table></center>
+
+<h2>Programs/SingleSource</h2>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+$SingleSourceProgramsTable
+</td></tr></table></center>
+
+</td></tr></html>
+
diff --git a/utils/OldenDataRecover.pl b/utils/OldenDataRecover.pl
new file mode 100644
index 000000000000..767839488b34
--- /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 000000000000..28709fefd319
--- /dev/null
+++ b/utils/PerfectShuffle/Makefile
@@ -0,0 +1,18 @@
+##===- utils/PerfectShuffle/Makefile -----------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TOOLNAME = llvm-PerfectShuffle
+NO_INSTALL = 1
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/utils/PerfectShuffle/PerfectShuffle.cpp b/utils/PerfectShuffle/PerfectShuffle.cpp
new file mode 100644
index 000000000000..26c4cf44c6e2
--- /dev/null
+++ b/utils/PerfectShuffle/PerfectShuffle.cpp
@@ -0,0 +1,497 @@
+//===-- PerfectShuffle.cpp - Perfect Shuffle Generator --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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>
+#include <cstdlib>
+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 000000000000..86b077780b0d
--- /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 000000000000..c615abad5068
--- /dev/null
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -0,0 +1,741 @@
+//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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;
+
+ // To make VS STL happy
+ AsmWriterOperand():OperandType(isLiteralTextOperand) {}
+
+ explicit 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) {
+ if (CurVariant == Variant || CurVariant == ~0U) {
+ for (; LastEmitted != DollarPos; ++LastEmitted)
+ switch (AsmString[LastEmitted]) {
+ case '\n': AddLiteralString("\\n"); break;
+ case '\t': AddLiteralString("\\t"); break;
+ case '"': AddLiteralString("\\\""); break;
+ case '\\': AddLiteralString("\\\\"); break;
+ default:
+ AddLiteralString(std::string(1, AsmString[LastEmitted]));
+ break;
+ }
+ } else {
+ LastEmitted = DollarPos;
+ }
+ } else if (AsmString[DollarPos] == '\\') {
+ if (DollarPos+1 != AsmString.size() &&
+ (CurVariant == Variant || CurVariant == ~0U)) {
+ if (AsmString[DollarPos+1] == 'n') {
+ AddLiteralString("\\n");
+ } else if (AsmString[DollarPos+1] == 't') {
+ AddLiteralString("\\t");
+ } else if (std::string("${|}\\").find(AsmString[DollarPos+1])
+ != std::string::npos) {
+ AddLiteralString(std::string(1, AsmString[DollarPos+1]));
+ } else {
+ throw "Non-supported escaped character found in instruction '" +
+ CGI.TheDef->getName() + "'!";
+ }
+ LastEmitted = DollarPos+2;
+ continue;
+ }
+ } 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, DBG_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+1);
+
+ // 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 << " processDebugLoc(MI->getDebugLoc());\n\n";
+
+ O << " if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {\n"
+ << " O << \"\\t\";\n"
+ << " printInlineAsm(MI);\n"
+ << " return true;\n"
+ << " } else if (MI->isLabel()) {\n"
+ << " printLabel(MI);\n"
+ << " return true;\n"
+ << " } else if (MI->getOpcode() == TargetInstrInfo::DECLARE) {\n"
+ << " printDeclare(MI);\n"
+ << " return true;\n"
+ << " } else if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF) {\n"
+ << " printImplicitDef(MI);\n"
+ << " return true;\n"
+ << " }\n\n";
+
+ O << " O << \"\\t\";\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 000000000000..302722d6df06
--- /dev/null
+++ b/utils/TableGen/AsmWriterEmitter.h
@@ -0,0 +1,50 @@
+//===- AsmWriterEmitter.h - Generate an assembly writer ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
new file mode 100644
index 000000000000..3f982e0c77ae
--- /dev/null
+++ b/utils/TableGen/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_executable(tblgen
+ AsmWriterEmitter.cpp
+ CallingConvEmitter.cpp
+ ClangDiagnosticsEmitter.cpp
+ CodeEmitterGen.cpp
+ CodeGenDAGPatterns.cpp
+ CodeGenInstruction.cpp
+ CodeGenTarget.cpp
+ DAGISelEmitter.cpp
+ FastISelEmitter.cpp
+ InstrEnumEmitter.cpp
+ InstrInfoEmitter.cpp
+ IntrinsicEmitter.cpp
+ LLVMCConfigurationEmitter.cpp
+ Record.cpp
+ RegisterInfoEmitter.cpp
+ SubtargetEmitter.cpp
+ TGLexer.cpp
+ TGParser.cpp
+ TGSourceMgr.cpp
+ TGValueTypes.cpp
+ TableGen.cpp
+ TableGenBackend.cpp
+ )
+
+target_link_libraries(tblgen LLVMSupport LLVMSystem)
+if( MINGW )
+ target_link_libraries(tblgen imagehlp psapi)
+endif( MINGW )
+if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD )
+ target_link_libraries(tblgen pthread)
+endif()
diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp
new file mode 100644
index 000000000000..c1f87014335f
--- /dev/null
+++ b/utils/TableGen/CallingConvEmitter.cpp
@@ -0,0 +1,206 @@
+//===- CallingConvEmitter.cpp - Generate calling conventions --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 ValVT,\n"
+ << std::string(CCs[i]->getName().size()+13, ' ')
+ << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n"
+ << std::string(CCs[i]->getName().size()+13, ' ')
+ << "ISD::ArgFlagsTy 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 ValVT,\n"
+ << std::string(CC->getName().size()+13, ' ')
+ << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n"
+ << std::string(CC->getName().size()+13, ' ')
+ << "ISD::ArgFlagsTy 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("CCAssignToRegWithShadow")) {
+ ListInit *RegList = Action->getValueAsListInit("RegList");
+ ListInit *ShadowRegList = Action->getValueAsListInit("ShadowRegList");
+ if (ShadowRegList->getSize() >0 &&
+ ShadowRegList->getSize() != RegList->getSize())
+ throw "Invalid length of list of shadowed registers";
+
+ if (RegList->getSize() == 1) {
+ O << IndentStr << "if (unsigned Reg = State.AllocateReg(";
+ O << getQualifiedName(RegList->getElementAsRecord(0));
+ O << ", " << getQualifiedName(ShadowRegList->getElementAsRecord(0));
+ O << ")) {\n";
+ } else {
+ unsigned RegListNumber = ++Counter;
+ unsigned ShadowRegListNumber = ++Counter;
+
+ O << IndentStr << "static const unsigned RegList" << RegListNumber
+ << "[] = {\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 << "static const unsigned RegList"
+ << ShadowRegListNumber << "[] = {\n";
+ O << IndentStr << " ";
+ for (unsigned i = 0, e = ShadowRegList->getSize(); i != e; ++i) {
+ if (i != 0) O << ", ";
+ O << getQualifiedName(ShadowRegList->getElementAsRecord(i));
+ }
+ O << "\n" << IndentStr << "};\n";
+
+ O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList"
+ << RegListNumber << ", " << "RegList" << ShadowRegListNumber
+ << ", " << 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(";
+ if (Size)
+ O << Size << ", ";
+ else
+ O << "\n" << IndentStr << " State.getTarget().getTargetData()"
+ "->getTypeAllocSize(LocVT.getTypeForMVT()), ";
+ if (Align)
+ O << Align;
+ else
+ O << "\n" << IndentStr << " State.getTarget().getTargetData()"
+ "->getABITypeAlignment(LocVT.getTypeForMVT())";
+ O << ");\n" << 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.isSExt())\n"
+ << IndentStr << IndentStr << "LocInfo = CCValAssign::SExt;\n"
+ << IndentStr << "else if (ArgFlags.isZExt())\n"
+ << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExt;\n"
+ << IndentStr << "else\n"
+ << IndentStr << IndentStr << "LocInfo = CCValAssign::AExt;\n";
+ } else if (Action->isSubClassOf("CCBitConvertToType")) {
+ Record *DestTy = Action->getValueAsDef("DestTy");
+ O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
+ O << IndentStr << "LocInfo = CCValAssign::BCvt;\n";
+ } else if (Action->isSubClassOf("CCPassByVal")) {
+ int Size = Action->getValueAsInt("Size");
+ int Align = Action->getValueAsInt("Align");
+ O << IndentStr
+ << "State.HandleByVal(ValNo, ValVT, LocVT, LocInfo, "
+ << Size << ", " << Align << ", ArgFlags);\n";
+ O << IndentStr << "return false;\n";
+ } else if (Action->isSubClassOf("CCCustom")) {
+ O << IndentStr
+ << "if (" << Action->getValueAsString("FuncName") << "(ValNo, ValVT, "
+ << "LocVT, LocInfo, ArgFlags, State))\n";
+ O << IndentStr << IndentStr << "return false;\n";
+ } else {
+ Action->dump();
+ throw "Unknown CCAction!";
+ }
+ }
+}
diff --git a/utils/TableGen/CallingConvEmitter.h b/utils/TableGen/CallingConvEmitter.h
new file mode 100644
index 000000000000..ffd6a48c7ad6
--- /dev/null
+++ b/utils/TableGen/CallingConvEmitter.h
@@ -0,0 +1,38 @@
+//===- CallingConvEmitter.h - Generate calling conventions ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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:
+ explicit 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/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
new file mode 100644
index 000000000000..919ae9befed3
--- /dev/null
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -0,0 +1,169 @@
+//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang diagnostics tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDiagnosticsEmitter.h"
+#include "Record.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/VectorExtras.h"
+#include <set>
+#include <map>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Warning Tables (.inc file) generation.
+//===----------------------------------------------------------------------===//
+
+void ClangDiagsDefsEmitter::run(std::ostream &OS) {
+ // Write the #if guard
+ if (!Component.empty()) {
+ std::string ComponentName = UppercaseString(Component);
+ OS << "#ifdef " << ComponentName << "START\n";
+ OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
+ << ",\n";
+ OS << "#undef " << ComponentName << "START\n";
+ OS << "#endif\n";
+ }
+
+ const std::vector<Record*> &Diags =
+ Records.getAllDerivedDefinitions("Diagnostic");
+
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ const Record &R = *Diags[i];
+ // Filter by component.
+ if (!Component.empty() && Component != R.getValueAsString("Component"))
+ continue;
+
+ OS << "DIAG(" << R.getName() << ", ";
+ OS << R.getValueAsDef("Class")->getName();
+ OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
+
+ // Description string.
+ OS << ", \"";
+ std::string S = R.getValueAsString("Text");
+ EscapeString(S);
+ OS << S << "\"";
+
+ // Warning associated with the diagnostic.
+ if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
+ S = DI->getDef()->getValueAsString("GroupName");
+ EscapeString(S);
+ OS << ", \"" << S << "\"";
+ } else {
+ OS << ", 0";
+ }
+ OS << ")\n";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Warning Group Tables generation
+//===----------------------------------------------------------------------===//
+
+struct GroupInfo {
+ std::vector<const Record*> DiagsInGroup;
+ std::vector<std::string> SubGroups;
+ unsigned IDNo;
+};
+
+void ClangDiagGroupsEmitter::run(std::ostream &OS) {
+ // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
+ // groups to diags in the group.
+ std::map<std::string, GroupInfo> DiagsInGroup;
+
+ std::vector<Record*> Diags =
+ Records.getAllDerivedDefinitions("Diagnostic");
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ const Record *R = Diags[i];
+ DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
+ if (DI == 0) continue;
+ std::string GroupName = DI->getDef()->getValueAsString("GroupName");
+ DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
+ }
+
+ // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
+ // groups (these are warnings that GCC supports that clang never produces).
+ Diags = Records.getAllDerivedDefinitions("DiagGroup");
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ Record *Group = Diags[i];
+ GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
+
+ std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
+ for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
+ GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
+ }
+
+ // Assign unique ID numbers to the groups.
+ unsigned IDNo = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
+ I->second.IDNo = IDNo;
+
+ // Walk through the groups emitting an array for each diagnostic of the diags
+ // that are mapped to.
+ OS << "\n#ifdef GET_DIAG_ARRAYS\n";
+ unsigned MaxLen = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+ MaxLen = std::max(MaxLen, (unsigned)I->first.size());
+
+ std::vector<const Record*> &V = I->second.DiagsInGroup;
+ if (!V.empty()) {
+ OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ OS << "diag::" << V[i]->getName() << ", ";
+ OS << "-1 };\n";
+ }
+
+ const std::vector<std::string> &SubGroups = I->second.SubGroups;
+ if (!SubGroups.empty()) {
+ OS << "static const char DiagSubGroup" << I->second.IDNo << "[] = { ";
+ for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
+ std::map<std::string, GroupInfo>::iterator RI =
+ DiagsInGroup.find(SubGroups[i]);
+ assert(RI != DiagsInGroup.end() && "Referenced without existing?");
+ OS << RI->second.IDNo << ", ";
+ }
+ OS << "-1 };\n";
+ }
+ }
+ OS << "#endif // GET_DIAG_ARRAYS\n\n";
+
+ // Emit the table now.
+ OS << "\n#ifdef GET_DIAG_TABLE\n";
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+ std::string S = I->first;
+ EscapeString(S);
+ // Group option string.
+ OS << " { \"" << S << "\","
+ << std::string(MaxLen-I->first.size()+1, ' ');
+
+ // Diagnostics in the group.
+ if (I->second.DiagsInGroup.empty())
+ OS << "0, ";
+ else
+ OS << "DiagArray" << I->second.IDNo << ", ";
+
+ // Subgroups.
+ if (I->second.SubGroups.empty())
+ OS << 0;
+ else
+ OS << "DiagSubGroup" << I->second.IDNo;
+ OS << " },\n";
+ }
+ OS << "#endif // GET_DIAG_TABLE\n\n";
+}
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.h b/utils/TableGen/ClangDiagnosticsEmitter.h
new file mode 100644
index 000000000000..58ea524d9647
--- /dev/null
+++ b/utils/TableGen/ClangDiagnosticsEmitter.h
@@ -0,0 +1,46 @@
+//===- ClangDiagnosticsEmitter.h - Generate Clang diagnostics tables -*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang diagnostics tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANGDIAGS_EMITTER_H
+#define CLANGDIAGS_EMITTER_H
+
+#include "TableGenBackend.h"
+
+namespace llvm {
+
+/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
+/// declarations of Clang diagnostics.
+///
+class ClangDiagsDefsEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ const std::string& Component;
+public:
+ explicit ClangDiagsDefsEmitter(RecordKeeper &R, const std::string& component)
+ : Records(R), Component(component) {}
+
+ // run - Output the .def file contents
+ void run(std::ostream &OS);
+};
+
+class ClangDiagGroupsEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ explicit ClangDiagGroupsEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(std::ostream &OS);
+};
+
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
new file mode 100644
index 000000000000..7b0a335b26be
--- /dev/null
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -0,0 +1,251 @@
+//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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() == "DBG_LABEL" ||
+ R->getName() == "EH_LABEL" ||
+ R->getName() == "GC_LABEL" ||
+ R->getName() == "DECLARE" ||
+ R->getName() == "EXTRACT_SUBREG" ||
+ R->getName() == "INSERT_SUBREG" ||
+ R->getName() == "IMPLICIT_DEF" ||
+ R->getName() == "SUBREG_TO_REG" ||
+ R->getName() == "COPY_TO_REGCLASS") 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(const 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 (R->getName() == "PHI" ||
+ R->getName() == "INLINEASM" ||
+ R->getName() == "DBG_LABEL" ||
+ R->getName() == "EH_LABEL" ||
+ R->getName() == "GC_LABEL" ||
+ R->getName() == "DECLARE" ||
+ R->getName() == "EXTRACT_SUBREG" ||
+ R->getName() == "INSERT_SUBREG" ||
+ R->getName() == "IMPLICIT_DEF" ||
+ R->getName() == "SUBREG_TO_REG" ||
+ R->getName() == "COPY_TO_REGCLASS") {
+ o << " 0U,\n";
+ 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," << '\t' << "// " << R->getName() << "\n";
+ }
+ o << " 0U\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 == "DBG_LABEL"||
+ InstName == "EH_LABEL"||
+ InstName == "GC_LABEL"||
+ InstName == "DECLARE"||
+ InstName == "EXTRACT_SUBREG" ||
+ InstName == "INSERT_SUBREG" ||
+ InstName == "IMPLICIT_DEF" ||
+ InstName == "SUBREG_TO_REG" ||
+ InstName == "COPY_TO_REGCLASS") 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 = ~0U >> (32-N);
+ 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 = 0;\n"
+ << " op = op; // suppress warning\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 000000000000..cb272bd56d25
--- /dev/null
+++ b/utils/TableGen/CodeEmitterGen.h
@@ -0,0 +1,43 @@
+//===- CodeEmitterGen.h - Code Emitter Generator ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
new file mode 100644
index 000000000000..db76dabb5375
--- /dev/null
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -0,0 +1,2395 @@
+//===- CodeGenDAGPatterns.cpp - Read DAG patterns from .td file -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the CodeGenDAGPatterns class, which is used to read and
+// represent the patterns present in a .td file for instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenDAGPatterns.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Streams.h"
+#include <set>
+#include <algorithm>
+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::SimpleValueType>
+FilterVTs(const std::vector<MVT::SimpleValueType> &InVTs, T Filter) {
+ std::vector<MVT::SimpleValueType> 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::SimpleValueType)InVTs[i]))
+ Result.push_back(InVTs[i]);
+ return Result;
+}
+
+static std::vector<unsigned char>
+ConvertVTs(const std::vector<MVT::SimpleValueType> &InVTs) {
+ std::vector<unsigned char> Result;
+ for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
+ Result.push_back(InVTs[i]);
+ return Result;
+}
+
+static inline bool isInteger(MVT::SimpleValueType VT) {
+ return MVT(VT).isInteger();
+}
+
+static inline bool isFloatingPoint(MVT::SimpleValueType VT) {
+ return MVT(VT).isFloatingPoint();
+}
+
+static inline bool isVector(MVT::SimpleValueType VT) {
+ return MVT(VT).isVector();
+}
+
+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;
+}
+
+namespace llvm {
+namespace EMVT {
+/// isExtIntegerInVTs - Return true if the specified extended value type vector
+/// contains isInt or an integer value type.
+bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs) {
+ assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!");
+ return EVTs[0] == isInt || !(FilterEVTs(EVTs, isInteger).empty());
+}
+
+/// isExtFloatingPointInVTs - Return true if the specified extended value type
+/// vector contains isFP or a FP value type.
+bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs) {
+ assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!");
+ return EVTs[0] == isFP || !(FilterEVTs(EVTs, isFloatingPoint).empty());
+}
+} // end namespace EMVT.
+} // end namespace llvm.
+
+
+/// Dependent variable map for CodeGenDAGPattern variant generation
+typedef std::map<std::string, int> DepVarMap;
+
+/// Const iterator shorthand for DepVarMap
+typedef DepVarMap::const_iterator DepVarMap_citer;
+
+namespace {
+void FindDepVarsOf(TreePatternNode *N, DepVarMap &DepMap) {
+ if (N->isLeaf()) {
+ if (dynamic_cast<DefInit*>(N->getLeafValue()) != NULL) {
+ DepMap[N->getName()]++;
+ }
+ } else {
+ for (size_t i = 0, e = N->getNumChildren(); i != e; ++i)
+ FindDepVarsOf(N->getChild(i), DepMap);
+ }
+}
+
+//! Find dependent variables within child patterns
+/*!
+ */
+void FindDepVars(TreePatternNode *N, MultipleUseVarSet &DepVars) {
+ DepVarMap depcounts;
+ FindDepVarsOf(N, depcounts);
+ for (DepVarMap_citer i = depcounts.begin(); i != depcounts.end(); ++i) {
+ if (i->second > 1) { // std::pair<std::string, int>
+ DepVars.insert(i->first);
+ }
+ }
+}
+
+//! Dump the dependent variable set:
+void DumpDepVars(MultipleUseVarSet &DepVars) {
+ if (DepVars.empty()) {
+ DOUT << "<empty set>";
+ } else {
+ DOUT << "[ ";
+ for (MultipleUseVarSet::const_iterator i = DepVars.begin(), e = DepVars.end();
+ i != e; ++i) {
+ DOUT << (*i) << " ";
+ }
+ DOUT << "]";
+ }
+}
+}
+
+//===----------------------------------------------------------------------===//
+// PatternToMatch implementation
+//
+
+/// getPredicateCheck - Return a single string containing all of this
+/// pattern's predicates concatenated with "&&" operators.
+///
+std::string PatternToMatch::getPredicateCheck() const {
+ 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") + ")";
+ }
+ }
+
+ return PredicateCheck;
+}
+
+//===----------------------------------------------------------------------===//
+// 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("SDTCisEltOfVec")) {
+ ConstraintType = SDTCisEltOfVec;
+ x.SDTCisEltOfVec_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.getDAGPatterns().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::SimpleValueType> IntVTs =
+ FilterVTs(CGT.getLegalValueTypes(), isInteger);
+
+ // If we found exactly one supported integer type, apply it.
+ if (IntVTs.size() == 1)
+ return NodeToApply->UpdateNodeType(IntVTs[0], TP);
+ return NodeToApply->UpdateNodeType(EMVT::isInt, TP);
+ }
+ case SDTCisFP: {
+ // If there is only one FP type supported, this must be it.
+ std::vector<MVT::SimpleValueType> FPVTs =
+ FilterVTs(CGT.getLegalValueTypes(), isFloatingPoint);
+
+ // If we found exactly one supported FP type, apply it.
+ if (FPVTs.size() == 1)
+ return NodeToApply->UpdateNodeType(FPVTs[0], TP);
+ return NodeToApply->UpdateNodeType(EMVT::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::SimpleValueType VT =
+ getValueType(static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef());
+ if (!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(EMVT::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(!(EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) &&
+ EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) &&
+ !(EMVT::isExtIntegerInVTs(BigOperand->getExtTypes()) &&
+ EMVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) &&
+ "SDTCisOpSmallerThanOp does not handle mixed int/fp types!");
+ if (EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes()))
+ MadeChange |= BigOperand->UpdateNodeType(EMVT::isInt, TP);
+ else if (EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes()))
+ MadeChange |= BigOperand->UpdateNodeType(EMVT::isFP, TP);
+ if (EMVT::isExtIntegerInVTs(BigOperand->getExtTypes()))
+ MadeChange |= NodeToApply->UpdateNodeType(EMVT::isInt, TP);
+ else if (EMVT::isExtFloatingPointInVTs(BigOperand->getExtTypes()))
+ MadeChange |= NodeToApply->UpdateNodeType(EMVT::isFP, TP);
+
+ std::vector<MVT::SimpleValueType> VTs = CGT.getLegalValueTypes();
+
+ if (EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) {
+ VTs = FilterVTs(VTs, isInteger);
+ } else if (EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) {
+ VTs = FilterVTs(VTs, 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 satisfy 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 SDTCisEltOfVec: {
+ TreePatternNode *OtherOperand =
+ getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum,
+ N, NumResults);
+ if (OtherOperand->hasTypeSet()) {
+ if (!isVector(OtherOperand->getTypeNum(0)))
+ TP.error(N->getOperator()->getName() + " VT operand must be a vector!");
+ MVT IVT = OtherOperand->getTypeNum(0);
+ IVT = IVT.getVectorElementType();
+ return NodeToApply->UpdateNodeType(IVT.getSimpleVT(), 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 if (PropList[i]->getName() == "SDNPMayStore") {
+ Properties |= 1 << SDNPMayStore;
+ } else if (PropList[i]->getName() == "SDNPMayLoad") {
+ Properties |= 1 << SDNPMayLoad;
+ } else if (PropList[i]->getName() == "SDNPSideEffect") {
+ Properties |= 1 << SDNPSideEffect;
+ } else if (PropList[i]->getName() == "SDNPMemOperand") {
+ Properties |= 1 << SDNPMemOperand;
+ } 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] == EMVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs))
+ return false;
+ if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) {
+ setTypes(ExtVTs);
+ return true;
+ }
+
+ if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) {
+ if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny ||
+ ExtVTs[0] == EMVT::isInt)
+ return false;
+ if (EMVT::isExtIntegerInVTs(ExtVTs)) {
+ std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, isInteger);
+ if (FVTs.size()) {
+ setTypes(ExtVTs);
+ return true;
+ }
+ }
+ }
+
+ if ((ExtVTs[0] == EMVT::isInt || ExtVTs[0] == MVT::iAny) &&
+ EMVT::isExtIntegerInVTs(getExtTypes())) {
+ assert(hasTypeSet() && "should be handled above!");
+ std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger);
+ if (getExtTypes() == FVTs)
+ return false;
+ setTypes(FVTs);
+ return true;
+ }
+ if ((ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny) &&
+ EMVT::isExtIntegerInVTs(getExtTypes())) {
+ //assert(hasTypeSet() && "should be handled above!");
+ std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger);
+ if (getExtTypes() == FVTs)
+ return false;
+ if (FVTs.size()) {
+ setTypes(FVTs);
+ return true;
+ }
+ }
+ if ((ExtVTs[0] == EMVT::isFP || ExtVTs[0] == MVT::fAny) &&
+ EMVT::isExtFloatingPointInVTs(getExtTypes())) {
+ assert(hasTypeSet() && "should be handled above!");
+ std::vector<unsigned char> FVTs =
+ FilterEVTs(getExtTypes(), 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) == EMVT::isInt || getExtTypeNum(0) == MVT::iAny) &&
+ EMVT::isExtIntegerInVTs(ExtVTs)) ||
+ ((getExtTypeNum(0) == EMVT::isFP || getExtTypeNum(0) == MVT::fAny) &&
+ EMVT::isExtFloatingPointInVTs(ExtVTs))) {
+ setTypes(ExtVTs);
+ return true;
+ }
+ if (getExtTypeNum(0) == EMVT::isInt &&
+ (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny)) {
+ 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 EMVT::isInt: OS << ":isInt"; break;
+ case EMVT::isFP : OS << ":isFP"; break;
+ case EMVT::isUnknown: ; /*OS << ":?";*/ break;
+ case MVT::iPTR: OS << ":iPTR"; break;
+ case MVT::iPTRAny: OS << ":iPTRAny"; 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 << ")";
+ }
+
+ for (unsigned i = 0, e = PredicateFns.size(); i != e; ++i)
+ OS << "<<P:" << PredicateFns[i] << ">>";
+ 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, the node's
+/// entire state is considered. The assigned name is ignored, since
+/// nodes with differing names are considered isomorphic. However, if
+/// the assigned name is present in the dependent variable set, then
+/// the assigned name is considered significant and the node is
+/// isomorphic if the names match.
+bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
+ const MultipleUseVarSet &DepVars) const {
+ if (N == this) return true;
+ if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() ||
+ getPredicateFns() != N->getPredicateFns() ||
+ 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())
+ && (DepVars.find(getName()) == DepVars.end()
+ || getName() == N->getName()));
+ }
+ }
+ 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), DepVars))
+ 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->setPredicateFns(getPredicateFns());
+ 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.
+ TreePatternNode *NewChild = ArgMap[Child->getName()];
+ assert(NewChild && "Couldn't find formal argument!");
+ assert((Child->getPredicateFns().empty() ||
+ NewChild->getPredicateFns() == Child->getPredicateFns()) &&
+ "Non-empty child predicate clobbered!");
+ setChild(i, NewChild);
+ }
+ } 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) {
+ TreePatternNode *Child = getChild(i);
+ TreePatternNode *NewChild = Child->InlinePatternFragments(TP);
+
+ assert((Child->getPredicateFns().empty() ||
+ NewChild->getPredicateFns() == Child->getPredicateFns()) &&
+ "Non-empty child predicate clobbered!");
+
+ setChild(i, NewChild);
+ }
+ return this;
+ }
+
+ // Otherwise, we found a reference to a fragment. First, look up its
+ // TreePattern record.
+ TreePattern *Frag = TP.getDAGPatterns().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();
+
+ std::string Code = Op->getValueAsCode("Predicate");
+ if (!Code.empty())
+ FragTree->addPredicateFn("Predicate_"+Op->getName());
+
+ // 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);
+
+ // Transfer in the old predicates.
+ for (unsigned i = 0, e = getPredicateFns().size(); i != e; ++i)
+ FragTree->addPredicateFn(getPredicateFns()[i]);
+
+ // Get a new copy of this fragment to stitch into here.
+ //delete this; // FIXME: implement refcounting!
+
+ // The fragment we inlined could have recursive inlining that is needed. See
+ // if there are any pattern fragments in it and inline them as needed.
+ return FragTree->InlinePatternFragments(TP);
+}
+
+/// 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, EMVT::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.getDAGPatterns().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.getDAGPatterns().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.getDAGPatterns().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;
+}
+
+
+/// getIntrinsicInfo - If this node corresponds to an intrinsic, return the
+/// CodeGenIntrinsic information for it, otherwise return a null pointer.
+const CodeGenIntrinsic *TreePatternNode::
+getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const {
+ if (getOperator() != CDP.get_intrinsic_void_sdnode() &&
+ getOperator() != CDP.get_intrinsic_w_chain_sdnode() &&
+ getOperator() != CDP.get_intrinsic_wo_chain_sdnode())
+ return 0;
+
+ unsigned IID =
+ dynamic_cast<IntInit*>(getChild(0)->getLeafValue())->getValue();
+ return &CDP.getIntrinsicInfo(IID);
+}
+
+/// isCommutativeIntrinsic - Return true if the node corresponds to a
+/// commutative intrinsic.
+bool
+TreePatternNode::isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const {
+ if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP))
+ return Int->isCommutative;
+ return false;
+}
+
+
+/// ApplyTypeConstraints - Apply all of the type constraints relevant 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) {
+ CodeGenDAGPatterns &CDP = TP.getDAGPatterns();
+ 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(EMVT::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::SimpleValueType 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 && VT != MVT::iPTRAny) {
+ unsigned Size = MVT(VT).getSizeInBits();
+ // 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()) {
+ // If sign-extended doesn't fit, does it fit as unsigned?
+ unsigned ValueMask;
+ unsigned UnsignedVal;
+ ValueMask = unsigned(~uint32_t(0UL) >> (32-Size));
+ UnsignedVal = unsigned(II->getValue());
+
+ if ((ValueMask & UnsignedVal) != UnsignedVal) {
+ TP.error("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 && "Missing RHS of a set?");
+ unsigned NC = getNumChildren();
+ bool MadeChange = false;
+ for (unsigned i = 0; i < NC-1; ++i) {
+ MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= getChild(NC-1)->ApplyTypeConstraints(TP, NotRegisters);
+
+ // Types of operands must match.
+ MadeChange |= getChild(i)->UpdateNodeType(getChild(NC-1)->getExtTypes(),
+ TP);
+ MadeChange |= getChild(NC-1)->UpdateNodeType(getChild(i)->getExtTypes(),
+ TP);
+ MadeChange |= UpdateNodeType(MVT::isVoid, TP);
+ }
+ return MadeChange;
+ } else if (getOperator()->getName() == "implicit" ||
+ getOperator()->getName() == "parallel") {
+ bool MadeChange = false;
+ for (unsigned i = 0; i < getNumChildren(); ++i)
+ MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= UpdateNodeType(MVT::isVoid, TP);
+ return MadeChange;
+ } else if (getOperator()->getName() == "COPY_TO_REGCLASS") {
+ bool MadeChange = false;
+ MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= UpdateNodeType(getChild(1)->getTypeNum(0), TP);
+ return MadeChange;
+ } else if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) {
+ bool MadeChange = false;
+
+ // Apply the result type to the node.
+ unsigned NumRetVTs = Int->IS.RetVTs.size();
+ unsigned NumParamVTs = Int->IS.ParamVTs.size();
+
+ for (unsigned i = 0, e = NumRetVTs; i != e; ++i)
+ MadeChange |= UpdateNodeType(Int->IS.RetVTs[i], TP);
+
+ if (getNumChildren() != NumParamVTs + NumRetVTs)
+ TP.error("Intrinsic '" + Int->Name + "' expects " +
+ utostr(NumParamVTs + NumRetVTs - 1) + " operands, not " +
+ utostr(getNumChildren() - 1) + " operands!");
+
+ // Apply type info to the intrinsic ID.
+ MadeChange |= getChild(0)->UpdateNodeType(MVT::iPTR, TP);
+
+ for (unsigned i = NumRetVTs, e = getNumChildren(); i != e; ++i) {
+ MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i - NumRetVTs];
+ MadeChange |= getChild(i)->UpdateNodeType(OpVT, TP);
+ MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
+ }
+ return MadeChange;
+ } else if (getOperator()->isSubClassOf("SDNode")) {
+ const SDNodeInfo &NI = CDP.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);
+
+ return MadeChange;
+ } else if (getOperator()->isSubClassOf("Instruction")) {
+ const DAGInstruction &Inst = CDP.getInstruction(getOperator());
+ bool MadeChange = false;
+ unsigned NumResults = Inst.getNumResults();
+
+ assert(NumResults <= 1 &&
+ "Only supports zero or one result instrs!");
+
+ CodeGenInstruction &InstInfo =
+ CDP.getTargetInfo().getInstruction(getOperator()->getName());
+ // Apply the result type to the node
+ if (NumResults == 0 || InstInfo.NumDefs == 0) {
+ 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 if (ResultNode->getName() == "unknown") {
+ std::vector<unsigned char> VT;
+ VT.push_back(EMVT::isUnknown);
+ MadeChange = UpdateNodeType(VT, TP);
+ } else {
+ assert(ResultNode->isSubClassOf("RegisterClass") &&
+ "Operands should be register classes!");
+
+ const CodeGenRegisterClass &RC =
+ CDP.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")) &&
+ !CDP.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::SimpleValueType VT;
+ TreePatternNode *Child = getChild(ChildNo++);
+ if (OperandNode->isSubClassOf("RegisterClass")) {
+ const CodeGenRegisterClass &RC =
+ CDP.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 if (OperandNode->getName() == "unknown") {
+ MadeChange |= Child->UpdateNodeType(EMVT::isUnknown, 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 sanity 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,
+ const CodeGenDAGPatterns &CDP) {
+ if (isLeaf()) return true;
+
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ if (!getChild(i)->canPatternMatch(Reason, CDP))
+ 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 = CDP.getSDNodeInfo(getOperator());
+ bool isCommIntrinsic = isCommutativeIntrinsic(CDP);
+ if (NodeInfo.hasProperty(SDNPCommutative) || isCommIntrinsic) {
+ // 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))) {
+ bool Skip = isCommIntrinsic ? 1 : 0; // First operand is intrinsic id.
+ for (unsigned i = Skip, 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,
+ CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){
+ 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,
+ CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){
+ isInputPattern = isInput;
+ Trees.push_back(ParseTreePattern(Pat));
+}
+
+TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput,
+ CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){
+ isInputPattern = isInput;
+ Trees.push_back(Pat);
+}
+
+
+
+void TreePattern::error(const std::string &Msg) const {
+ dump();
+ throw TGError(TheRecord->getLoc(), "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);
+ if (New->getNumChildren() == 0)
+ 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" &&
+ Operator->getName() != "implicit" &&
+ Operator->getName() != "parallel")
+ 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 = getDAGPatterns().getIntrinsic(Operator);
+ unsigned IID = getDAGPatterns().getIntrinsicID(Operator)+1;
+
+ // If this intrinsic returns void, it must have side-effects and thus a
+ // chain.
+ if (Int.IS.RetVTs[0] == MVT::isVoid) {
+ Operator = getDAGPatterns().get_intrinsic_void_sdnode();
+ } else if (Int.ModRef != CodeGenIntrinsic::NoMem) {
+ // Has side-effects, requires chain.
+ Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode();
+ } else {
+ // Otherwise, no chain.
+ Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode();
+ }
+
+ TreePatternNode *IIDNode = new TreePatternNode(new IntInit(IID));
+ Children.insert(Children.begin(), IIDNode);
+ }
+
+ TreePatternNode *Result = new TreePatternNode(Operator, Children);
+ Result->setName(Dag->getName());
+ return Result;
+}
+
+/// InferAllTypes - Infer/propagate as many types throughout the expression
+/// patterns as possible. Return true if all types are inferred, 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()); }
+
+//===----------------------------------------------------------------------===//
+// CodeGenDAGPatterns implementation
+//
+
+// FIXME: REMOVE OSTREAM ARGUMENT
+CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) {
+ Intrinsics = LoadIntrinsics(Records, false);
+ TgtIntrinsics = LoadIntrinsics(Records, true);
+ ParseNodeInfo();
+ ParseNodeTransforms();
+ ParseComplexPatterns();
+ ParsePatternFragments();
+ ParseDefaultOperands();
+ ParseInstructions();
+ ParsePatterns();
+
+ // Generate variants. For example, commutative patterns can match
+ // multiple ways. Add them to PatternsToMatch as well.
+ GenerateVariants();
+
+ // Infer instruction flags. For example, we can detect loads,
+ // stores, and side effects in many cases by examining an
+ // instruction's pattern.
+ InferInstructionFlags();
+}
+
+CodeGenDAGPatterns::~CodeGenDAGPatterns() {
+ for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(),
+ E = PatternFragments.end(); I != E; ++I)
+ delete I->second;
+}
+
+
+Record *CodeGenDAGPatterns::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;
+}
+
+// Parse all of the SDNode definitions for the target, populating SDNodes.
+void CodeGenDAGPatterns::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 builtin 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 CodeGenDAGPatterns::ParseNodeTransforms() {
+ 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, NodeXForm(SDNode, Code)));
+
+ Xforms.pop_back();
+ }
+}
+
+void CodeGenDAGPatterns::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.
+///
+void CodeGenDAGPatterns::ParsePatternFragments() {
+ std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrag");
+
+ // First step, parse all of the fragments.
+ 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 set, to discard duplicates.
+ std::vector<std::string> &Args = P->getArgList();
+ std::set<std::string> OperandsSet(Args.begin(), Args.end());
+
+ if (OperandsSet.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());
+ // Special cases: ops == outs == ins. Different names are used to
+ // improve readability.
+ if (!OpsOp ||
+ (OpsOp->getDef()->getName() != "ops" &&
+ OpsOp->getDef()->getName() != "outs" &&
+ OpsOp->getDef()->getName() != "ins"))
+ 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 (!OperandsSet.count(OpsList->getArgName(j)))
+ P->error("'" + OpsList->getArgName(j) +
+ "' does not occur in pattern or was multiply specified!");
+ OperandsSet.erase(OpsList->getArgName(j));
+ Args.push_back(OpsList->getArgName(j));
+ }
+
+ if (!OperandsSet.empty())
+ P->error("Operands list does not contain an entry for operand '" +
+ *OperandsSet.begin() + "'!");
+
+ // If there is a code init for this fragment, keep track of the fact that
+ // this fragment uses it.
+ std::string Code = Fragments[i]->getValueAsCode("Predicate");
+ if (!Code.empty())
+ P->getOnlyTree()->addPredicateFn("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);
+ }
+
+ // 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 (unsigned i = 0, e = Fragments.size(); i != e; ++i) {
+ TreePattern *ThePat = PatternFragments[Fragments[i]];
+ 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 CodeGenDAGPatterns::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 {
+ 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 CodeGenDAGPatterns::
+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() == "implicit") {
+ for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Dest = Pat->getChild(i);
+ if (!Dest->isLeaf())
+ I->error("implicitly defined value should be a register!");
+
+ DefInit *Val = dynamic_cast<DefInit*>(Dest->getLeafValue());
+ if (!Val || !Val->getDef()->isSubClassOf("Register"))
+ I->error("implicitly defined value should be a register!");
+ InstImpResults.push_back(Val->getDef());
+ }
+ 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 = 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!");
+
+ if (Pat->getTransformFn())
+ I->error("Cannot specify a transform function on a set node!");
+
+ // Check the set destinations.
+ unsigned NumDests = Pat->getNumChildren()-1;
+ for (unsigned i = 0; i != NumDests; ++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(NumDests),
+ InstInputs, InstResults,
+ InstImpInputs, InstImpResults);
+}
+
+//===----------------------------------------------------------------------===//
+// Instruction Analysis
+//===----------------------------------------------------------------------===//
+
+class InstAnalyzer {
+ const CodeGenDAGPatterns &CDP;
+ bool &mayStore;
+ bool &mayLoad;
+ bool &HasSideEffects;
+public:
+ InstAnalyzer(const CodeGenDAGPatterns &cdp,
+ bool &maystore, bool &mayload, bool &hse)
+ : CDP(cdp), mayStore(maystore), mayLoad(mayload), HasSideEffects(hse){
+ }
+
+ /// Analyze - Analyze the specified instruction, returning true if the
+ /// instruction had a pattern.
+ bool Analyze(Record *InstRecord) {
+ const TreePattern *Pattern = CDP.getInstruction(InstRecord).getPattern();
+ if (Pattern == 0) {
+ HasSideEffects = 1;
+ return false; // No pattern.
+ }
+
+ // FIXME: Assume only the first tree is the pattern. The others are clobber
+ // nodes.
+ AnalyzeNode(Pattern->getTree(0));
+ return true;
+ }
+
+private:
+ void AnalyzeNode(const TreePatternNode *N) {
+ if (N->isLeaf()) {
+ if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
+ Record *LeafRec = DI->getDef();
+ // Handle ComplexPattern leaves.
+ if (LeafRec->isSubClassOf("ComplexPattern")) {
+ const ComplexPattern &CP = CDP.getComplexPattern(LeafRec);
+ if (CP.hasProperty(SDNPMayStore)) mayStore = true;
+ if (CP.hasProperty(SDNPMayLoad)) mayLoad = true;
+ if (CP.hasProperty(SDNPSideEffect)) HasSideEffects = true;
+ }
+ }
+ return;
+ }
+
+ // Analyze children.
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
+ AnalyzeNode(N->getChild(i));
+
+ // Ignore set nodes, which are not SDNodes.
+ if (N->getOperator()->getName() == "set")
+ return;
+
+ // Get information about the SDNode for the operator.
+ const SDNodeInfo &OpInfo = CDP.getSDNodeInfo(N->getOperator());
+
+ // Notice properties of the node.
+ if (OpInfo.hasProperty(SDNPMayStore)) mayStore = true;
+ if (OpInfo.hasProperty(SDNPMayLoad)) mayLoad = true;
+ if (OpInfo.hasProperty(SDNPSideEffect)) HasSideEffects = true;
+
+ if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) {
+ // If this is an intrinsic, analyze it.
+ if (IntInfo->ModRef >= CodeGenIntrinsic::ReadArgMem)
+ mayLoad = true;// These may load memory.
+
+ if (IntInfo->ModRef >= CodeGenIntrinsic::WriteArgMem)
+ mayStore = true;// Intrinsics that can write to memory are 'mayStore'.
+
+ if (IntInfo->ModRef >= CodeGenIntrinsic::WriteMem)
+ // WriteMem intrinsics can have other strange effects.
+ HasSideEffects = true;
+ }
+ }
+
+};
+
+static void InferFromPattern(const CodeGenInstruction &Inst,
+ bool &MayStore, bool &MayLoad,
+ bool &HasSideEffects,
+ const CodeGenDAGPatterns &CDP) {
+ MayStore = MayLoad = HasSideEffects = false;
+
+ bool HadPattern =
+ InstAnalyzer(CDP, MayStore, MayLoad, HasSideEffects).Analyze(Inst.TheDef);
+
+ // InstAnalyzer only correctly analyzes mayStore/mayLoad so far.
+ if (Inst.mayStore) { // If the .td file explicitly sets mayStore, use it.
+ // If we decided that this is a store from the pattern, then the .td file
+ // entry is redundant.
+ if (MayStore)
+ fprintf(stderr,
+ "Warning: mayStore flag explicitly set on instruction '%s'"
+ " but flag already inferred from pattern.\n",
+ Inst.TheDef->getName().c_str());
+ MayStore = true;
+ }
+
+ if (Inst.mayLoad) { // If the .td file explicitly sets mayLoad, use it.
+ // If we decided that this is a load from the pattern, then the .td file
+ // entry is redundant.
+ if (MayLoad)
+ fprintf(stderr,
+ "Warning: mayLoad flag explicitly set on instruction '%s'"
+ " but flag already inferred from pattern.\n",
+ Inst.TheDef->getName().c_str());
+ MayLoad = true;
+ }
+
+ if (Inst.neverHasSideEffects) {
+ if (HadPattern)
+ fprintf(stderr, "Warning: neverHasSideEffects set on instruction '%s' "
+ "which already has a pattern\n", Inst.TheDef->getName().c_str());
+ HasSideEffects = false;
+ }
+
+ if (Inst.hasSideEffects) {
+ if (HasSideEffects)
+ fprintf(stderr, "Warning: hasSideEffects set on instruction '%s' "
+ "which already inferred this.\n", Inst.TheDef->getName().c_str());
+ HasSideEffects = true;
+ }
+}
+
+/// ParseInstructions - Parse all of the instructions, inlining and resolving
+/// any fragments involved. This populates the Instructions list with fully
+/// resolved instructions.
+void CodeGenDAGPatterns::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) {
+ if (InstInfo.NumDefs == 0) {
+ // 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->clearPredicateFns();
+
+ // 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.
+ // FIXME: InstImpResults and InstImpInputs should not be part of
+ // DAGInstruction.
+ 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;
+ const TreePattern *I = TheInst.getPattern();
+ if (I == 0) continue; // No pattern.
+
+ // FIXME: Assume only the first tree is the pattern. The others are clobber
+ // nodes.
+ TreePatternNode *Pattern = I->getTree(0);
+ TreePatternNode *SrcPattern;
+ if (Pattern->getOperator()->getName() == "set") {
+ SrcPattern = Pattern->getChild(Pattern->getNumChildren()-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, TheInst.getImpResults(),
+ Instr->getValueAsInt("AddedComplexity")));
+ }
+}
+
+
+void CodeGenDAGPatterns::InferInstructionFlags() {
+ std::map<std::string, CodeGenInstruction> &InstrDescs =
+ Target.getInstructions();
+ for (std::map<std::string, CodeGenInstruction>::iterator
+ II = InstrDescs.begin(), E = InstrDescs.end(); II != E; ++II) {
+ CodeGenInstruction &InstInfo = II->second;
+ // Determine properties of the instruction from its pattern.
+ bool MayStore, MayLoad, HasSideEffects;
+ InferFromPattern(InstInfo, MayStore, MayLoad, HasSideEffects, *this);
+ InstInfo.mayStore = MayStore;
+ InstInfo.mayLoad = MayLoad;
+ InstInfo.hasSideEffects = HasSideEffects;
+ }
+}
+
+void CodeGenDAGPatterns::ParsePatterns() {
+ std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern");
+
+ for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
+ DagInit *Tree = Patterns[i]->getValueAsDag("PatternToMatch");
+ DefInit *OpDef = dynamic_cast<DefInit*>(Tree->getOperator());
+ Record *Operator = OpDef->getDef();
+ TreePattern *Pattern;
+ if (Operator->getName() != "parallel")
+ Pattern = new TreePattern(Patterns[i], Tree, true, *this);
+ else {
+ std::vector<Init*> Values;
+ for (unsigned j = 0, ee = Tree->getNumArgs(); j != ee; ++j)
+ Values.push_back(Tree->getArg(j));
+ ListInit *LI = new ListInit(Values);
+ Pattern = new TreePattern(Patterns[i], LI, 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->getTree(0)->
+ UpdateNodeType(Result->getTree(0)->getExtTypes(), *Result);
+ IterateInference |= Result->getTree(0)->
+ UpdateNodeType(Pattern->getTree(0)->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;
+ for (unsigned j = 0, ee = Pattern->getNumTrees(); j != ee; ++j)
+ FindPatternInputsAndOutputs(Pattern, Pattern->getTree(j),
+ InstInputs, InstResults,
+ InstImpInputs, InstImpResults);
+
+ // Promote the xform function to be an explicit node if set.
+ TreePatternNode *DstPattern = Result->getOnlyTree();
+ std::vector<TreePatternNode*> ResultNodeOperands;
+ 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->getTree(0)->canPatternMatch(Reason, *this))
+ Pattern->error("Pattern can never match: " + Reason);
+
+ PatternsToMatch.
+ push_back(PatternToMatch(Patterns[i]->getValueAsListInit("Predicates"),
+ Pattern->getTree(0),
+ Temp.getOnlyTree(), InstImpResults,
+ 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,
+ CodeGenDAGPatterns &CDP,
+ const MultipleUseVarSet &DepVars) {
+ // 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;
+ do {
+#ifndef NDEBUG
+ if (DebugFlag && !Idxs.empty()) {
+ cerr << Orig->getOperator()->getName() << ": Idxs = [ ";
+ for (unsigned i = 0; i < Idxs.size(); ++i) {
+ cerr << Idxs[i] << " ";
+ }
+ cerr << "]\n";
+ }
+#endif
+ // 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->setPredicateFns(Orig->getPredicateFns());
+ R->setTransformFn(Orig->getTransformFn());
+ R->setTypes(Orig->getExtTypes());
+
+ // If this pattern cannot match, do not include it as a variant.
+ std::string ErrString;
+ if (!R->canPatternMatch(ErrString, CDP)) {
+ 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], DepVars)) {
+ AlreadyExists = true;
+ break;
+ }
+
+ if (AlreadyExists)
+ delete R;
+ else
+ OutVariants.push_back(R);
+ }
+
+ // Increment indices to the next permutation by incrementing the
+ // indicies from last index backward, e.g., generate the sequence
+ // [0, 0], [0, 1], [1, 0], [1, 1].
+ int IdxsIdx;
+ for (IdxsIdx = Idxs.size() - 1; IdxsIdx >= 0; --IdxsIdx) {
+ if (++Idxs[IdxsIdx] == ChildVariants[IdxsIdx].size())
+ Idxs[IdxsIdx] = 0;
+ else
+ break;
+ }
+ NotDone = (IdxsIdx >= 0);
+ } while (NotDone);
+}
+
+/// 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,
+ CodeGenDAGPatterns &CDP,
+ const MultipleUseVarSet &DepVars) {
+ std::vector<std::vector<TreePatternNode*> > ChildVariants;
+ ChildVariants.push_back(LHS);
+ ChildVariants.push_back(RHS);
+ CombineChildVariants(Orig, ChildVariants, OutVariants, CDP, DepVars);
+}
+
+
+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->getPredicateFns().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,
+ CodeGenDAGPatterns &CDP,
+ const MultipleUseVarSet &DepVars) {
+ // We cannot permute leaves.
+ if (N->isLeaf()) {
+ OutVariants.push_back(N);
+ return;
+ }
+
+ // Look up interesting info about the node.
+ const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(N->getOperator());
+
+ // If this node is associative, re-associate.
+ if (NodeInfo.hasProperty(SDNPAssociative)) {
+ // Re-associate 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, CDP, DepVars);
+ GenerateVariantsOf(MaximalChildren[1], BVariants, CDP, DepVars);
+ GenerateVariantsOf(MaximalChildren[2], CVariants, CDP, DepVars);
+
+ // 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, CDP, DepVars);
+ CombineChildVariants(N, BVariants, AVariants, BAVariants, CDP, DepVars);
+ CombineChildVariants(N, AVariants, CVariants, ACVariants, CDP, DepVars);
+ CombineChildVariants(N, CVariants, AVariants, CAVariants, CDP, DepVars);
+ CombineChildVariants(N, BVariants, CVariants, BCVariants, CDP, DepVars);
+ CombineChildVariants(N, CVariants, BVariants, CBVariants, CDP, DepVars);
+
+ // Combine those into the result: (x op x) op x
+ CombineChildVariants(N, ABVariants, CVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, BAVariants, CVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, ACVariants, BVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, CAVariants, BVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, BCVariants, AVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, CBVariants, AVariants, OutVariants, CDP, DepVars);
+
+ // Combine those into the result: x op (x op x)
+ CombineChildVariants(N, CVariants, ABVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, CVariants, BAVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, BVariants, ACVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, BVariants, CAVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, AVariants, BCVariants, OutVariants, CDP, DepVars);
+ CombineChildVariants(N, AVariants, CBVariants, OutVariants, CDP, DepVars);
+ 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], CDP, DepVars);
+
+ // Build all permutations based on how the children were formed.
+ CombineChildVariants(N, ChildVariants, OutVariants, CDP, DepVars);
+
+ // If this node is commutative, consider the commuted order.
+ bool isCommIntrinsic = N->isCommutativeIntrinsic(CDP);
+ if (NodeInfo.hasProperty(SDNPCommutative) || isCommIntrinsic) {
+ assert((N->getNumChildren()==2 || isCommIntrinsic) &&
+ "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 (isCommIntrinsic) {
+ // Commutative intrinsic. First operand is the intrinsic id, 2nd and 3rd
+ // operands are the commutative operands, and there might be more operands
+ // after those.
+ assert(NC >= 3 &&
+ "Commutative intrinsic should have at least 3 childrean!");
+ std::vector<std::vector<TreePatternNode*> > Variants;
+ Variants.push_back(ChildVariants[0]); // Intrinsic id.
+ Variants.push_back(ChildVariants[2]);
+ Variants.push_back(ChildVariants[1]);
+ for (unsigned i = 3; i != NC; ++i)
+ Variants.push_back(ChildVariants[i]);
+ CombineChildVariants(N, Variants, OutVariants, CDP, DepVars);
+ } else if (NC == 2)
+ CombineChildVariants(N, ChildVariants[1], ChildVariants[0],
+ OutVariants, CDP, DepVars);
+ }
+}
+
+
+// GenerateVariants - Generate variants. For example, commutative patterns can
+// match multiple ways. Add them to PatternsToMatch as well.
+void CodeGenDAGPatterns::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 aggressive 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) {
+ MultipleUseVarSet DepVars;
+ std::vector<TreePatternNode*> Variants;
+ FindDepVars(PatternsToMatch[i].getSrcPattern(), DepVars);
+ DOUT << "Dependent/multiply used variables: ";
+ DEBUG(DumpDepVars(DepVars));
+ DOUT << "\n";
+ GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, DepVars);
+
+ 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(), DepVars)) {
+ 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].getDstRegs(),
+ PatternsToMatch[i].getAddedComplexity()));
+ }
+
+ DOUT << "\n";
+ }
+}
+
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
new file mode 100644
index 000000000000..9ce14dcc7b36
--- /dev/null
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -0,0 +1,597 @@
+//===- CodeGenDAGPatterns.h - Read DAG patterns from .td file ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the CodeGenDAGPatterns class, which is used to read and
+// represent the patterns present in a .td file for instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEGEN_DAGPATTERNS_H
+#define CODEGEN_DAGPATTERNS_H
+
+#include <set>
+#include <algorithm>
+#include <vector>
+
+#include "CodeGenTarget.h"
+#include "CodeGenIntrinsics.h"
+
+namespace llvm {
+ class Record;
+ struct Init;
+ class ListInit;
+ class DagInit;
+ class SDNodeInfo;
+ class TreePattern;
+ class TreePatternNode;
+ class CodeGenDAGPatterns;
+ class ComplexPattern;
+
+/// EMVT::DAGISelGenValueType - These are some extended forms of
+/// MVT::SimpleValueType that we use as lattice values during type inference.
+namespace EMVT {
+ enum DAGISelGenValueType {
+ isFP = MVT::LAST_VALUETYPE,
+ isInt,
+ isUnknown
+ };
+
+ /// isExtIntegerVT - Return true if the specified extended value type vector
+ /// contains isInt or an integer value type.
+ bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs);
+
+ /// isExtFloatingPointVT - Return true if the specified extended value type
+ /// vector contains isFP or a FP value type.
+ bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs);
+}
+
+/// Set type used to track multiply used variables in patterns
+typedef std::set<std::string> MultipleUseVarSet;
+
+/// 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, SDTCisEltOfVec
+ } ConstraintType;
+
+ union { // The discriminated union.
+ struct {
+ unsigned char VT;
+ } SDTCisVT_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisSameAs_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisVTSmallerThanOp_Info;
+ struct {
+ unsigned BigOperandNum;
+ } SDTCisOpSmallerThanOp_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisEltOfVec_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 EMVT::isUnknown if it hasn't
+ /// been determined yet. This is a std::vector because during inference
+ /// there may be multiple possible types.
+ 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;
+
+ /// PredicateFns - The predicate functions to execute on this node to check
+ /// for a match. If this list is empty, no predicate is involved.
+ std::vector<std::string> PredicateFns;
+
+ /// 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(EMVT::isUnknown); }
+ TreePatternNode(Init *val) // leaf ctor
+ : Types(), Operator(0), Val(val), TransformFn(0) {
+ Types.push_back(EMVT::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) ||
+ (Types[0] == MVT::iPTRAny);
+ }
+ bool isTypeCompletelyUnknown() const {
+ return Types[0] == EMVT::isUnknown;
+ }
+ bool isTypeDynamicallyResolved() const {
+ return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny);
+ }
+ MVT::SimpleValueType getTypeNum(unsigned Num) const {
+ assert(hasTypeSet() && "Doesn't have a type yet!");
+ assert(Types.size() > Num && "Type num out of range!");
+ return (MVT::SimpleValueType)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, EMVT::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::vector<std::string> &getPredicateFns() const { return PredicateFns; }
+ void clearPredicateFns() { PredicateFns.clear(); }
+ void setPredicateFns(const std::vector<std::string> &Fns) {
+ assert(PredicateFns.empty() && "Overwriting non-empty predicate list!");
+ PredicateFns = Fns;
+ }
+ void addPredicateFn(const std::string &Fn) {
+ assert(!Fn.empty() && "Empty predicate string!");
+ if (std::find(PredicateFns.begin(), PredicateFns.end(), Fn) ==
+ PredicateFns.end())
+ PredicateFns.push_back(Fn);
+ }
+
+ Record *getTransformFn() const { return TransformFn; }
+ void setTransformFn(Record *Fn) { TransformFn = Fn; }
+
+ /// getIntrinsicInfo - If this node corresponds to an intrinsic, return the
+ /// CodeGenIntrinsic information for it, otherwise return a null pointer.
+ const CodeGenIntrinsic *getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const;
+
+ /// isCommutativeIntrinsic - Return true if the node is an intrinsic which is
+ /// marked isCommutative.
+ bool isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const;
+
+ 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 MultipleUseVarSet &DepVars) 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 relevant 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, const CodeGenDAGPatterns &CDP);
+};
+
+
+/// 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;
+
+ /// CDP - the top-level object coordinating this madness.
+ ///
+ CodeGenDAGPatterns &CDP;
+
+ /// 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,
+ CodeGenDAGPatterns &ise);
+ TreePattern(Record *TheRec, DagInit *Pat, bool isInput,
+ CodeGenDAGPatterns &ise);
+ TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput,
+ CodeGenDAGPatterns &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; }
+
+ CodeGenDAGPatterns &getDAGPatterns() const { return CDP; }
+
+ /// 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 inferred, 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) {}
+
+ const 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(); }
+ const std::vector<Record*>& getImpResults() const { return ImpResults; }
+
+ 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 CodeGenDAGPatterns to keep tab of patterns
+/// processed to produce isel.
+struct PatternToMatch {
+ PatternToMatch(ListInit *preds,
+ TreePatternNode *src, TreePatternNode *dst,
+ const std::vector<Record*> &dstregs,
+ unsigned complexity):
+ Predicates(preds), SrcPattern(src), DstPattern(dst), Dstregs(dstregs),
+ AddedComplexity(complexity) {};
+
+ ListInit *Predicates; // Top level predicate conditions to match.
+ TreePatternNode *SrcPattern; // Source pattern to match.
+ TreePatternNode *DstPattern; // Resulting pattern.
+ std::vector<Record*> Dstregs; // Physical register defs being matched.
+ unsigned AddedComplexity; // Add to matching pattern complexity.
+
+ ListInit *getPredicates() const { return Predicates; }
+ TreePatternNode *getSrcPattern() const { return SrcPattern; }
+ TreePatternNode *getDstPattern() const { return DstPattern; }
+ const std::vector<Record*> &getDstRegs() const { return Dstregs; }
+ unsigned getAddedComplexity() const { return AddedComplexity; }
+
+ std::string getPredicateCheck() const;
+};
+
+
+class CodeGenDAGPatterns {
+ RecordKeeper &Records;
+ CodeGenTarget Target;
+ std::vector<CodeGenIntrinsic> Intrinsics;
+ std::vector<CodeGenIntrinsic> TgtIntrinsics;
+
+ 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:
+ CodeGenDAGPatterns(RecordKeeper &R);
+ ~CodeGenDAGPatterns();
+
+ CodeGenTarget &getTargetInfo() { return Target; }
+ 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;
+ }
+
+ // Node transformation lookups.
+ typedef std::pair<Record*, std::string> NodeXForm;
+ const NodeXForm &getSDNodeTransform(Record *R) const {
+ assert(SDNodeXForms.count(R) && "Invalid transform!");
+ return SDNodeXForms.find(R)->second;
+ }
+
+ typedef std::map<Record*, NodeXForm>::const_iterator nx_iterator;
+ nx_iterator nx_begin() const { return SDNodeXForms.begin(); }
+ nx_iterator nx_end() const { return SDNodeXForms.end(); }
+
+
+ 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];
+ for (unsigned i = 0, e = TgtIntrinsics.size(); i != e; ++i)
+ if (TgtIntrinsics[i].TheDef == R) return TgtIntrinsics[i];
+ assert(0 && "Unknown intrinsic!");
+ abort();
+ }
+
+ const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const {
+ if (IID-1 < Intrinsics.size())
+ return Intrinsics[IID-1];
+ if (IID-Intrinsics.size()-1 < TgtIntrinsics.size())
+ return TgtIntrinsics[IID-Intrinsics.size()-1];
+ assert(0 && "Bad intrinsic ID!");
+ abort();
+ }
+
+ unsigned getIntrinsicID(Record *R) const {
+ for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i)
+ if (Intrinsics[i].TheDef == R) return i;
+ for (unsigned i = 0, e = TgtIntrinsics.size(); i != e; ++i)
+ if (TgtIntrinsics[i].TheDef == R) return i + Intrinsics.size();
+ 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;
+ }
+
+ // Pattern Fragment information.
+ TreePattern *getPatternFragment(Record *R) const {
+ assert(PatternFragments.count(R) && "Invalid pattern fragment request!");
+ return PatternFragments.find(R)->second;
+ }
+ typedef std::map<Record*, TreePattern*>::const_iterator pf_iterator;
+ pf_iterator pf_begin() const { return PatternFragments.begin(); }
+ pf_iterator pf_end() const { return PatternFragments.end(); }
+
+ // Patterns to match information.
+ typedef std::vector<PatternToMatch>::const_iterator ptm_iterator;
+ ptm_iterator ptm_begin() const { return PatternsToMatch.begin(); }
+ ptm_iterator ptm_end() const { return PatternsToMatch.end(); }
+
+
+
+ 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();
+ void ParseComplexPatterns();
+ void ParsePatternFragments();
+ void ParseDefaultOperands();
+ void ParseInstructions();
+ void ParsePatterns();
+ void InferInstructionFlags();
+ 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);
+};
+} // end namespace llvm
+
+#endif
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
new file mode 100644
index 000000000000..4650b88fd517
--- /dev/null
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -0,0 +1,273 @@
+//===- CodeGenInstruction.cpp - CodeGen Instruction Class Wrapper ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the CodeGenInstruction class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenInstruction.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include <set>
+using namespace llvm;
+
+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::size_type start = CStr.find_first_not_of(" \t");
+ std::string Name = CStr.substr(start, 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) {
+ Namespace = R->getValueAsString("Namespace");
+
+ isReturn = R->getValueAsBit("isReturn");
+ isBranch = R->getValueAsBit("isBranch");
+ isIndirectBranch = R->getValueAsBit("isIndirectBranch");
+ isBarrier = R->getValueAsBit("isBarrier");
+ isCall = R->getValueAsBit("isCall");
+ canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
+ mayLoad = R->getValueAsBit("mayLoad");
+ mayStore = R->getValueAsBit("mayStore");
+ 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");
+ isNotDuplicable = R->getValueAsBit("isNotDuplicable");
+ hasSideEffects = R->getValueAsBit("hasSideEffects");
+ mayHaveSideEffects = R->getValueAsBit("mayHaveSideEffects");
+ neverHasSideEffects = R->getValueAsBit("neverHasSideEffects");
+ isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove");
+ hasOptionalDef = false;
+ isVariadic = false;
+
+ if (mayHaveSideEffects + neverHasSideEffects + hasSideEffects > 1)
+ throw R->getName() + ": multiple conflicting side-effect flags set!";
+
+ DagInit *DI;
+ try {
+ DI = R->getValueAsDag("OutOperandList");
+ } catch (...) {
+ // Error getting operand list, just ignore it (sparcv9).
+ AsmString.clear();
+ OperandList.clear();
+ return;
+ }
+ NumDefs = DI->getNumArgs();
+
+ DagInit *IDI;
+ try {
+ IDI = R->getValueAsDag("InOperandList");
+ } catch (...) {
+ // Error getting operand list, just ignore it (sparcv9).
+ AsmString.clear();
+ OperandList.clear();
+ return;
+ }
+ DI = (DagInit*)(new BinOpInit(BinOpInit::CONCAT, DI, IDI, new DagRecTy))->Fold(R, 0);
+
+ 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") {
+ isVariadic = true;
+ continue;
+ } else if (!Rec->isSubClassOf("RegisterClass") &&
+ Rec->getName() != "ptr_rc" && Rec->getName() != "unknown")
+ throw "Unknown operand class '" + Rec->getName() +
+ "' in '" + 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 + "'";
+}
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
new file mode 100644
index 000000000000..f4afd5e45ba3
--- /dev/null
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -0,0 +1,153 @@
+//===- CodeGenInstruction.h - Instruction Class Wrapper ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 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) {}
+ };
+
+ /// NumDefs - Number of def operands declared.
+ ///
+ unsigned NumDefs;
+
+ /// 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 isIndirectBranch;
+ bool isBarrier;
+ bool isCall;
+ bool canFoldAsLoad;
+ bool mayLoad, mayStore;
+ bool isPredicable;
+ bool isConvertibleToThreeAddress;
+ bool isCommutable;
+ bool isTerminator;
+ bool isReMaterializable;
+ bool hasDelaySlot;
+ bool usesCustomDAGSchedInserter;
+ bool isVariadic;
+ bool hasCtrlDep;
+ bool isNotDuplicable;
+ bool hasOptionalDef;
+ bool hasSideEffects;
+ bool mayHaveSideEffects;
+ bool neverHasSideEffects;
+ bool isAsCheapAsAMove;
+
+ /// 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 000000000000..7e7bdf989acf
--- /dev/null
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -0,0 +1,87 @@
+//===- CodeGenIntrinsic.h - Intrinsic Class Wrapper ------------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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.
+
+ /// IntrinsicSignature - This structure holds the return values and
+ /// parameter values of an intrinsic. If the number of return values is > 1,
+ /// then the intrinsic implicitly returns a first-class aggregate. The
+ /// numbering of the types starts at 0 with the first return value and
+ /// continues from there through the parameter list. This is useful for
+ /// "matching" types.
+ struct IntrinsicSignature {
+ /// RetVTs - The MVT::SimpleValueType for each return 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::SimpleValueType> RetVTs;
+
+ /// RetTypeDefs - The records for each return type.
+ std::vector<Record*> RetTypeDefs;
+
+ /// ParamVTs - The MVT::SimpleValueType for each parameter 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::SimpleValueType> ParamVTs;
+
+ /// ParamTypeDefs - The records for each parameter type.
+ std::vector<Record*> ParamTypeDefs;
+ };
+
+ IntrinsicSignature IS;
+
+ // 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;
+
+ /// isCommutative - True if the intrinsic is commutative.
+ bool isCommutative;
+
+ enum ArgAttribute {
+ NoCapture
+ };
+ std::vector<std::pair<unsigned, ArgAttribute> > ArgumentAttributes;
+
+ CodeGenIntrinsic(Record *R);
+ };
+
+ /// LoadIntrinsics - Read all of the intrinsics defined in the specified
+ /// .td file.
+ std::vector<CodeGenIntrinsic> LoadIntrinsics(const RecordKeeper &RC,
+ bool TargetOnly);
+}
+
+#endif
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
new file mode 100644
index 000000000000..6f8682be59d3
--- /dev/null
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -0,0 +1,61 @@
+//===- CodeGenRegisters.h - Register and RegisterClass Info -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "llvm/CodeGen/ValueTypes.h"
+#include <string>
+#include <vector>
+#include <cstdlib>
+
+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::SimpleValueType> VTs;
+ unsigned SpillSize;
+ unsigned SpillAlignment;
+ int CopyCost;
+ std::vector<Record*> SubRegClasses;
+ std::string MethodProtos, MethodBodies;
+
+ const std::string &getName() const;
+ const std::vector<MVT::SimpleValueType> &getValueTypes() const {return VTs;}
+ unsigned getNumValueTypes() const { return VTs.size(); }
+
+ MVT::SimpleValueType 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 000000000000..aad1be941622
--- /dev/null
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -0,0 +1,576 @@
+//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class wraps 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 <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 MVT::SimpleValueType that the specified TableGen
+/// record corresponds to.
+MVT::SimpleValueType llvm::getValueType(Record *Rec) {
+ return (MVT::SimpleValueType)Rec->getValueAsInt("Value");
+}
+
+std::string llvm::getName(MVT::SimpleValueType 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::fAny: return "MVT::fAny";
+ 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::ppcf128: return "MVT::ppcf128";
+ case MVT::Flag: return "MVT::Flag";
+ case MVT::isVoid:return "MVT::isVoid";
+ case MVT::v2i8: return "MVT::v2i8";
+ case MVT::v4i8: return "MVT::v4i8";
+ case MVT::v2i16: return "MVT::v2i16";
+ 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::v3i32: return "MVT::v3i32";
+ case MVT::v3f32: return "MVT::v3f32";
+ case MVT::iPTR: return "TLI.getPointerTy()";
+ case MVT::iPTRAny: return "TLI.getPointerTy()";
+ default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
+ }
+}
+
+std::string llvm::getEnumName(MVT::SimpleValueType 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::fAny: return "MVT::fAny";
+ 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::ppcf128: return "MVT::ppcf128";
+ case MVT::Flag: return "MVT::Flag";
+ case MVT::isVoid:return "MVT::isVoid";
+ case MVT::v2i8: return "MVT::v2i8";
+ case MVT::v4i8: return "MVT::v4i8";
+ case MVT::v2i16: return "MVT::v2i16";
+ 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::v3i32: return "MVT::v3i32";
+ case MVT::v3f32: return "MVT::v3f32";
+ case MVT::iPTR: return "MVT::iPTR";
+ case MVT::iPTRAny: return "MVT::iPTRAny";
+ default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
+ }
+}
+
+/// getQualifiedName - Return the name of the specified record, with a
+/// namespace qualifier if the record contains one.
+///
+std::string llvm::getQualifiedName(const Record *R) {
+ std::string Namespace = R->getValueAsString("Namespace");
+ if (Namespace.empty()) return R->getName();
+ return Namespace + "::" + R->getName();
+}
+
+
+
+
+/// 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();
+}
+
+std::string CodeGenTarget::getInstNamespace() const {
+ std::string InstNS;
+
+ for (inst_iterator i = inst_begin(), e = inst_end(); i != e; ++i) {
+ InstNS = i->second.Namespace;
+
+ // Make sure not to pick up "TargetInstrInfo" by accidentally getting
+ // the namespace off the PHI instruction or something.
+ if (InstNS != "TargetInstrInfo")
+ break;
+ }
+
+ return InstNS;
+}
+
+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::SimpleValueType> &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(VTs[0]).getSizeInBits();
+ SpillAlignment = R->getValueAsInt("Alignment");
+ CopyCost = R->getValueAsInt("CopyCost");
+ 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("DBG_LABEL");
+ if (I == Instructions.end()) throw "Could not find 'DBG_LABEL' instruction!";
+ const CodeGenInstruction *DBG_LABEL = &I->second;
+
+ I = getInstructions().find("EH_LABEL");
+ if (I == Instructions.end()) throw "Could not find 'EH_LABEL' instruction!";
+ const CodeGenInstruction *EH_LABEL = &I->second;
+
+ I = getInstructions().find("GC_LABEL");
+ if (I == Instructions.end()) throw "Could not find 'GC_LABEL' instruction!";
+ const CodeGenInstruction *GC_LABEL = &I->second;
+
+ I = getInstructions().find("DECLARE");
+ if (I == Instructions.end()) throw "Could not find 'DECLARE' instruction!";
+ const CodeGenInstruction *DECLARE = &I->second;
+
+ I = getInstructions().find("EXTRACT_SUBREG");
+ if (I == Instructions.end())
+ throw "Could not find 'EXTRACT_SUBREG' instruction!";
+ const CodeGenInstruction *EXTRACT_SUBREG = &I->second;
+
+ I = getInstructions().find("INSERT_SUBREG");
+ if (I == Instructions.end())
+ throw "Could not find 'INSERT_SUBREG' instruction!";
+ const CodeGenInstruction *INSERT_SUBREG = &I->second;
+
+ I = getInstructions().find("IMPLICIT_DEF");
+ if (I == Instructions.end())
+ throw "Could not find 'IMPLICIT_DEF' instruction!";
+ const CodeGenInstruction *IMPLICIT_DEF = &I->second;
+
+ I = getInstructions().find("SUBREG_TO_REG");
+ if (I == Instructions.end())
+ throw "Could not find 'SUBREG_TO_REG' instruction!";
+ const CodeGenInstruction *SUBREG_TO_REG = &I->second;
+
+ I = getInstructions().find("COPY_TO_REGCLASS");
+ if (I == Instructions.end())
+ throw "Could not find 'COPY_TO_REGCLASS' instruction!";
+ const CodeGenInstruction *COPY_TO_REGCLASS = &I->second;
+
+ // Print out the rest of the instructions now.
+ NumberedInstructions.push_back(PHI);
+ NumberedInstructions.push_back(INLINEASM);
+ NumberedInstructions.push_back(DBG_LABEL);
+ NumberedInstructions.push_back(EH_LABEL);
+ NumberedInstructions.push_back(GC_LABEL);
+ NumberedInstructions.push_back(DECLARE);
+ NumberedInstructions.push_back(EXTRACT_SUBREG);
+ NumberedInstructions.push_back(INSERT_SUBREG);
+ NumberedInstructions.push_back(IMPLICIT_DEF);
+ NumberedInstructions.push_back(SUBREG_TO_REG);
+ NumberedInstructions.push_back(COPY_TO_REGCLASS);
+ for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II)
+ if (&II->second != PHI &&
+ &II->second != INLINEASM &&
+ &II->second != DBG_LABEL &&
+ &II->second != EH_LABEL &&
+ &II->second != GC_LABEL &&
+ &II->second != DECLARE &&
+ &II->second != EXTRACT_SUBREG &&
+ &II->second != INSERT_SUBREG &&
+ &II->second != IMPLICIT_DEF &&
+ &II->second != SUBREG_TO_REG &&
+ &II->second != COPY_TO_REGCLASS)
+ 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");
+}
+
+//===----------------------------------------------------------------------===//
+// 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 if (PropList[i]->getName() == "SDNPMayStore") {
+ Properties |= 1 << SDNPMayStore;
+ } else if (PropList[i]->getName() == "SDNPMayLoad") {
+ Properties |= 1 << SDNPMayLoad;
+ } else if (PropList[i]->getName() == "SDNPSideEffect") {
+ Properties |= 1 << SDNPSideEffect;
+ } else if (PropList[i]->getName() == "SDNPMemOperand") {
+ Properties |= 1 << SDNPMemOperand;
+ } else {
+ cerr << "Unsupported SD Node property '" << PropList[i]->getName()
+ << "' on ComplexPattern '" << R->getName() << "'!\n";
+ exit(1);
+ }
+
+ // Parse the attributes.
+ Attributes = 0;
+ PropList = R->getValueAsListOfDefs("Attributes");
+ for (unsigned i = 0, e = PropList.size(); i != e; ++i)
+ if (PropList[i]->getName() == "CPAttrParentAsRoot") {
+ Attributes |= 1 << CPAttrParentAsRoot;
+ } else {
+ cerr << "Unsupported pattern attribute '" << PropList[i]->getName()
+ << "' on ComplexPattern '" << R->getName() << "'!\n";
+ exit(1);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// CodeGenIntrinsic Implementation
+//===----------------------------------------------------------------------===//
+
+std::vector<CodeGenIntrinsic> llvm::LoadIntrinsics(const RecordKeeper &RC,
+ bool TargetOnly) {
+ std::vector<Record*> I = RC.getAllDerivedDefinitions("Intrinsic");
+
+ std::vector<CodeGenIntrinsic> Result;
+
+ for (unsigned i = 0, e = I.size(); i != e; ++i) {
+ bool isTarget = I[i]->getValueAsBit("isTarget");
+ if (isTarget == TargetOnly)
+ Result.push_back(CodeGenIntrinsic(I[i]));
+ }
+ return Result;
+}
+
+CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
+ TheDef = R;
+ std::string DefName = R->getName();
+ ModRef = WriteMem;
+ isOverloaded = false;
+ isCommutative = 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)
+ Name += (EnumName[i] == '_') ? '.' : 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 return types.
+ std::vector<MVT::SimpleValueType> OverloadedVTs;
+ ListInit *TypeList = R->getValueAsListInit("RetTypes");
+ for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
+ Record *TyEl = TypeList->getElementAsRecord(i);
+ assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
+ MVT::SimpleValueType VT;
+ if (TyEl->isSubClassOf("LLVMMatchType")) {
+ unsigned MatchTy = TyEl->getValueAsInt("Number");
+ assert(MatchTy < OverloadedVTs.size() &&
+ "Invalid matching number!");
+ VT = OverloadedVTs[MatchTy];
+ // It only makes sense to use the extended and truncated vector element
+ // variants with iAny types; otherwise, if the intrinsic is not
+ // overloaded, all the types can be specified directly.
+ assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") &&
+ !TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) ||
+ VT == MVT::iAny) && "Expected iAny type");
+ } else {
+ VT = getValueType(TyEl->getValueAsDef("VT"));
+ }
+ if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) {
+ OverloadedVTs.push_back(VT);
+ isOverloaded |= true;
+ }
+ IS.RetVTs.push_back(VT);
+ IS.RetTypeDefs.push_back(TyEl);
+ }
+
+ if (IS.RetVTs.size() == 0)
+ throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!";
+
+ // Parse the list of parameter types.
+ TypeList = R->getValueAsListInit("ParamTypes");
+ for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
+ Record *TyEl = TypeList->getElementAsRecord(i);
+ assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
+ MVT::SimpleValueType VT;
+ if (TyEl->isSubClassOf("LLVMMatchType")) {
+ unsigned MatchTy = TyEl->getValueAsInt("Number");
+ assert(MatchTy < OverloadedVTs.size() &&
+ "Invalid matching number!");
+ VT = OverloadedVTs[MatchTy];
+ // It only makes sense to use the extended and truncated vector element
+ // variants with iAny types; otherwise, if the intrinsic is not
+ // overloaded, all the types can be specified directly.
+ assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") &&
+ !TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) ||
+ VT == MVT::iAny) && "Expected iAny type");
+ } else
+ VT = getValueType(TyEl->getValueAsDef("VT"));
+ if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) {
+ OverloadedVTs.push_back(VT);
+ isOverloaded |= true;
+ }
+ IS.ParamVTs.push_back(VT);
+ IS.ParamTypeDefs.push_back(TyEl);
+ }
+
+ // 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 if (Property->getName() == "Commutative")
+ isCommutative = true;
+ else if (Property->isSubClassOf("NoCapture")) {
+ unsigned ArgNo = Property->getValueAsInt("ArgNo");
+ ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
+ } else
+ assert(0 && "Unknown property!");
+ }
+}
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
new file mode 100644
index 000000000000..c7cc77ccd41a
--- /dev/null
+++ b/utils/TableGen/CodeGenTarget.h
@@ -0,0 +1,243 @@
+//===- CodeGenTarget.h - Target Class Wrapper -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 <algorithm>
+#include <iosfwd>
+#include <map>
+
+namespace llvm {
+
+class Record;
+class RecordKeeper;
+struct CodeGenRegister;
+class CodeGenTarget;
+
+// SelectionDAG node properties.
+// SDNPMemOperand: indicates that a node touches memory and therefore must
+// have an associated memory operand that describes the access.
+enum SDNP {
+ SDNPCommutative,
+ SDNPAssociative,
+ SDNPHasChain,
+ SDNPOutFlag,
+ SDNPInFlag,
+ SDNPOptInFlag,
+ SDNPMayLoad,
+ SDNPMayStore,
+ SDNPSideEffect,
+ SDNPMemOperand
+};
+
+// ComplexPattern attributes.
+enum CPAttr { CPAttrParentAsRoot };
+
+/// getValueType - Return the MVT::SimpleValueType that the specified TableGen
+/// record corresponds to.
+MVT::SimpleValueType getValueType(Record *Rec);
+
+std::string getName(MVT::SimpleValueType T);
+std::string getEnumName(MVT::SimpleValueType T);
+
+/// getQualifiedName - Return the name of the specified record, with a
+/// namespace qualifier if the record contains one.
+std::string getQualifiedName(const Record *R);
+
+/// 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::SimpleValueType> 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;
+
+ /// getInstNamespace - Return the target-specific instruction namespace.
+ ///
+ std::string getInstNamespace() 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 the register is not in a register
+ /// class, return null. If the register is in multiple classes, and the
+ /// classes have a superset-subset relationship and the same set of
+ /// types, return the superclass. Otherwise 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])
+ continue;
+
+ // If a register's classes have different types, return null.
+ if (FoundRC && RC.getValueTypes() != FoundRC->getValueTypes())
+ return 0;
+
+ // If this is the first class that contains the register,
+ // make a note of it and go on to the next class.
+ if (!FoundRC) {
+ FoundRC = &RC;
+ break;
+ }
+
+ std::vector<Record *> Elements(RC.Elements);
+ std::vector<Record *> FoundElements(FoundRC->Elements);
+ std::sort(Elements.begin(), Elements.end());
+ std::sort(FoundElements.begin(), FoundElements.end());
+
+ // Check to see if the previously found class that contains
+ // the register is a subclass of the current class. If so,
+ // prefer the superclass.
+ if (std::includes(Elements.begin(), Elements.end(),
+ FoundElements.begin(), FoundElements.end())) {
+ FoundRC = &RC;
+ break;
+ }
+
+ // Check to see if the previously found class that contains
+ // the register is a superclass of the current class. If so,
+ // prefer the superclass.
+ if (std::includes(FoundElements.begin(), FoundElements.end(),
+ Elements.begin(), Elements.end()))
+ break;
+
+ // Multiple classes, and neither is a superclass of the other.
+ // Return null.
+ return 0;
+ }
+ }
+ return FoundRC;
+ }
+
+ /// getRegisterVTs - Find the union of all possible SimpleValueTypes for the
+ /// specified physical register.
+ std::vector<unsigned char> getRegisterVTs(Record *R) const;
+
+ const std::vector<MVT::SimpleValueType> &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::SimpleValueType VT) const {
+ const std::vector<MVT::SimpleValueType> &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;
+ }
+ std::map<std::string, CodeGenInstruction> &getInstructions() {
+ 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::SimpleValueType Ty;
+ unsigned NumOperands;
+ std::string SelectFunc;
+ std::vector<Record*> RootNodes;
+ unsigned Properties; // Node properties
+ unsigned Attributes; // Pattern attributes
+public:
+ ComplexPattern() : NumOperands(0) {};
+ ComplexPattern(Record *R);
+
+ MVT::SimpleValueType 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); }
+ bool hasAttribute(enum CPAttr Attr) const { return Attributes & (1 << Attr); }
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
new file mode 100644
index 000000000000..0e2e61596f69
--- /dev/null
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -0,0 +1,2131 @@
+//===- DAGISelEmitter.cpp - Generate an instruction selector --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Streams.h"
+#include <algorithm>
+#include <deque>
+using namespace llvm;
+
+namespace {
+ cl::opt<bool>
+ GenDebug("gen-debug", cl::desc("Generate debug code"),
+ cl::init(false));
+}
+
+//===----------------------------------------------------------------------===//
+// DAGISelEmitter Helper methods
+//
+
+/// 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,
+ CodeGenDAGPatterns &CGP) {
+ if (N->isLeaf() &&
+ dynamic_cast<DefInit*>(N->getLeafValue()) &&
+ static_cast<DefInit*>(N->getLeafValue())->getDef()->
+ isSubClassOf("ComplexPattern")) {
+ return &CGP.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, CodeGenDAGPatterns &CGP) {
+ assert((EMVT::isExtIntegerInVTs(P->getExtTypes()) ||
+ EMVT::isExtFloatingPointInVTs(P->getExtTypes()) ||
+ P->getExtTypeNum(0) == MVT::isVoid ||
+ P->getExtTypeNum(0) == MVT::Flag ||
+ P->getExtTypeNum(0) == MVT::iPTR ||
+ P->getExtTypeNum(0) == MVT::iPTRAny) &&
+ "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, CGP);
+ 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->getPredicateFns().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, CGP);
+ 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, CGP);
+ else if (!Child->getPredicateFns().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,
+ CodeGenDAGPatterns &CGP) {
+ if (P->isLeaf()) return 0;
+
+ unsigned Cost = 0;
+ Record *Op = P->getOperator();
+ if (Op->isSubClassOf("Instruction")) {
+ Cost++;
+ CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op->getName());
+ if (II.usesCustomDAGSchedInserter)
+ Cost += 10;
+ }
+ for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
+ Cost += getResultPatternCost(P->getChild(i), CGP);
+ return Cost;
+}
+
+/// getResultPatternCodeSize - Compute the code size of instructions for this
+/// pattern.
+static unsigned getResultPatternSize(TreePatternNode *P,
+ CodeGenDAGPatterns &CGP) {
+ 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), CGP);
+ 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(CodeGenDAGPatterns &cgp) : CGP(cgp) {}
+ CodeGenDAGPatterns &CGP;
+
+ typedef std::pair<unsigned, std::string> CodeLine;
+ typedef std::vector<CodeLine> CodeList;
+ typedef std::vector<std::pair<const PatternToMatch*, CodeList> > PatternList;
+
+ bool operator()(const std::pair<const PatternToMatch*, CodeList> &LHSPair,
+ const std::pair<const PatternToMatch*, CodeList> &RHSPair) {
+ const PatternToMatch *LHS = LHSPair.first;
+ const PatternToMatch *RHS = RHSPair.first;
+
+ unsigned LHSSize = getPatternSize(LHS->getSrcPattern(), CGP);
+ unsigned RHSSize = getPatternSize(RHS->getSrcPattern(), CGP);
+ 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(), CGP);
+ unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), CGP);
+ if (LHSCost < RHSCost) return true;
+ if (LHSCost > RHSCost) return false;
+
+ return getResultPatternSize(LHS->getDstPattern(), CGP) <
+ getResultPatternSize(RHS->getDstPattern(), CGP);
+ }
+};
+
+/// getRegisterValueType - Look up and return the ValueType of the specified
+/// register. If the register is a member of multiple register classes which
+/// have different associated types, return MVT::Other.
+static MVT::SimpleValueType getRegisterValueType(Record *R, const CodeGenTarget &T) {
+ bool FoundRC = false;
+ MVT::SimpleValueType VT = MVT::Other;
+ const std::vector<CodeGenRegisterClass> &RCs = T.getRegisterClasses();
+ std::vector<CodeGenRegisterClass>::const_iterator RC;
+ std::vector<Record*>::const_iterator Element;
+
+ for (RC = RCs.begin() ; RC != RCs.end() ; RC++) {
+ Element = find((*RC).Elements.begin(), (*RC).Elements.end(), R);
+ if (Element != (*RC).Elements.end()) {
+ if (!FoundRC) {
+ FoundRC = true;
+ VT = (*RC).getValueTypeNum(0);
+ } else {
+ // In multiple RC's
+ if (VT != (*RC).getValueTypeNum(0)) {
+ // Types of the RC's do not agree. Return MVT::Other. The
+ // target is responsible for handling this.
+ return MVT::Other;
+ }
+ }
+ }
+ }
+ return VT;
+}
+
+
+/// 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));
+}
+
+/// NodeHasProperty - return true if TreePatternNode has the specified
+/// property.
+static bool NodeHasProperty(TreePatternNode *N, SDNP Property,
+ CodeGenDAGPatterns &CGP) {
+ if (N->isLeaf()) {
+ const ComplexPattern *CP = NodeGetComplexPattern(N, CGP);
+ if (CP)
+ return CP->hasProperty(Property);
+ return false;
+ }
+ Record *Operator = N->getOperator();
+ if (!Operator->isSubClassOf("SDNode")) return false;
+
+ return CGP.getSDNodeInfo(Operator).hasProperty(Property);
+}
+
+static bool PatternHasProperty(TreePatternNode *N, SDNP Property,
+ CodeGenDAGPatterns &CGP) {
+ if (NodeHasProperty(N, Property, CGP))
+ return true;
+
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = N->getChild(i);
+ if (PatternHasProperty(Child, Property, CGP))
+ return true;
+ }
+
+ return false;
+}
+
+static std::string getOpcodeName(Record *Op, CodeGenDAGPatterns &CGP) {
+ return CGP.getSDNodeInfo(Op).getEnumName();
+}
+
+static
+bool DisablePatternForFastISel(TreePatternNode *N, CodeGenDAGPatterns &CGP) {
+ bool isStore = !N->isLeaf() &&
+ getOpcodeName(N->getOperator(), CGP) == "ISD::STORE";
+ if (!isStore && NodeHasProperty(N, SDNPHasChain, CGP))
+ return false;
+
+ bool HasChain = false;
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = N->getChild(i);
+ if (PatternHasProperty(Child, SDNPHasChain, CGP)) {
+ HasChain = true;
+ break;
+ }
+ }
+ return HasChain;
+}
+
+//===----------------------------------------------------------------------===//
+// Node Transformation emitter implementation.
+//
+void DAGISelEmitter::EmitNodeTransforms(std::ostream &OS) {
+ // Walk the pattern fragments, adding them to a map, which sorts them by
+ // name.
+ typedef std::map<std::string, CodeGenDAGPatterns::NodeXForm> NXsByNameTy;
+ NXsByNameTy NXsByName;
+
+ for (CodeGenDAGPatterns::nx_iterator I = CGP.nx_begin(), E = CGP.nx_end();
+ I != E; ++I)
+ NXsByName.insert(std::make_pair(I->first->getName(), I->second));
+
+ OS << "\n// Node transformations.\n";
+
+ for (NXsByNameTy::iterator I = NXsByName.begin(), E = NXsByName.end();
+ I != E; ++I) {
+ Record *SDNode = I->second.first;
+ std::string Code = I->second.second;
+
+ if (Code.empty()) continue; // Empty code? Skip it.
+
+ std::string ClassName = CGP.getSDNodeInfo(SDNode).getSDClassName();
+ const char *C2 = ClassName == "SDNode" ? "N" : "inN";
+
+ OS << "inline SDValue Transform_" << I->first << "(SDNode *" << C2
+ << ") {\n";
+ if (ClassName != "SDNode")
+ OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n";
+ OS << Code << "\n}\n";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Predicate emitter implementation.
+//
+
+void DAGISelEmitter::EmitPredicateFunctions(std::ostream &OS) {
+ OS << "\n// Predicate functions.\n";
+
+ // Walk the pattern fragments, adding them to a map, which sorts them by
+ // name.
+ typedef std::map<std::string, std::pair<Record*, TreePattern*> > PFsByNameTy;
+ PFsByNameTy PFsByName;
+
+ for (CodeGenDAGPatterns::pf_iterator I = CGP.pf_begin(), E = CGP.pf_end();
+ I != E; ++I)
+ PFsByName.insert(std::make_pair(I->first->getName(), *I));
+
+
+ for (PFsByNameTy::iterator I = PFsByName.begin(), E = PFsByName.end();
+ I != E; ++I) {
+ Record *PatFragRecord = I->second.first;// Record that derives from PatFrag.
+ TreePattern *P = I->second.second;
+
+ // If there is a code init for this fragment, emit the predicate code.
+ std::string Code = PatFragRecord->getValueAsCode("Predicate");
+ if (Code.empty()) continue;
+
+ if (P->getOnlyTree()->isLeaf())
+ OS << "inline bool Predicate_" << PatFragRecord->getName()
+ << "(SDNode *N) {\n";
+ else {
+ std::string ClassName =
+ CGP.getSDNodeInfo(P->getOnlyTree()->getOperator()).getSDClassName();
+ const char *C2 = ClassName == "SDNode" ? "N" : "inN";
+
+ OS << "inline bool Predicate_" << PatFragRecord->getName()
+ << "(SDNode *" << C2 << ") {\n";
+ if (ClassName != "SDNode")
+ OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n";
+ }
+ OS << Code << "\n}\n";
+ }
+
+ OS << "\n\n";
+}
+
+
+//===----------------------------------------------------------------------===//
+// PatternCodeEmitter implementation.
+//
+class PatternCodeEmitter {
+private:
+ CodeGenDAGPatterns &CGP;
+
+ // Predicates.
+ std::string PredicateCheck;
+ // 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;
+ // Name of the folded node which produces a flag.
+ std::pair<std::string, unsigned> FoldedFlag;
+ // 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;
+
+ /// LSI - Load/Store information.
+ /// Save loads/stores matched by a pattern, and generate a MemOperandSDNode
+ /// for each memory access. This facilitates the use of AliasAnalysis in
+ /// the backend.
+ std::vector<std::string> LSI;
+
+ /// 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 SDValue 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;
+ /// OutputIsVariadic - Records whether the instruction output pattern uses
+ /// variable_ops. This requires that the Emit function be passed an
+ /// additional argument to indicate where the input varargs operands
+ /// begin.
+ bool &OutputIsVariadic;
+ /// NumInputRootOps - Records the number of operands the root node of the
+ /// input pattern has. This information is used in the generated code to
+ /// pass to Emit functions when variable_ops processing is needed.
+ unsigned &NumInputRootOps;
+
+ 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(CodeGenDAGPatterns &cgp, std::string predcheck,
+ 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,
+ bool &oiv,
+ unsigned &niro)
+ : CGP(cgp), PredicateCheck(predcheck), Pattern(pattern), Instruction(instr),
+ GeneratedCode(gc), GeneratedDecl(gd),
+ TargetOpcodes(to), TargetVTs(tv),
+ OutputIsVariadic(oiv), NumInputRootOps(niro),
+ 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) {
+
+ // Save loads/stores matched by a pattern.
+ if (!N->isLeaf() && N->getName().empty()) {
+ if (NodeHasProperty(N, SDNPMemOperand, CGP))
+ LSI.push_back(RootName);
+ }
+
+ bool isRoot = (P == NULL);
+ // Emit instruction predicates. Each predicate is just a string for now.
+ if (isRoot) {
+ // Record input varargs info.
+ NumInputRootOps = N->getNumChildren();
+
+ if (DisablePatternForFastISel(N, CGP))
+ emitCheck("OptLevel != CodeGenOpt::None");
+
+ emitCheck(PredicateCheck);
+ }
+
+ if (N->isLeaf()) {
+ if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
+ emitCheck("cast<ConstantSDNode>(" + RootName +
+ ")->getSExtValue() == INT64_C(" +
+ 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, CGP);
+ bool HasChain = PatternHasProperty(N, SDNPHasChain, CGP);
+ 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 = P != Pattern;
+ if (!NeedCheck) {
+ const SDNodeInfo &PInfo = CGP.getSDNodeInfo(P->getOperator());
+ NeedCheck =
+ P->getOperator() == CGP.get_intrinsic_void_sdnode() ||
+ P->getOperator() == CGP.get_intrinsic_w_chain_sdnode() ||
+ P->getOperator() == CGP.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("IsLegalAndProfitableToFold(" + RootName +
+ ".getNode(), " + ParentName + ".getNode(), N.getNode())");
+ }
+ }
+ }
+
+ if (NodeHasChain) {
+ if (FoundChain) {
+ emitCheck("(" + ChainName + ".getNode() == " + RootName + ".getNode() || "
+ "IsChainCompatible(" + ChainName + ".getNode(), " +
+ RootName + ".getNode()))");
+ OrigChains.push_back(std::make_pair(ChainName, RootName));
+ } else
+ FoundChain = true;
+ ChainName = "Chain" + ChainSuffix;
+ emitInit("SDValue " + 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, CGP) ||
+ PatternHasProperty(N, SDNPOptInFlag, CGP) ||
+ PatternHasProperty(N, SDNPOutFlag, CGP))) {
+ if (!EmittedUseCheck) {
+ // Multiple uses of actual result?
+ emitCheck(RootName + ".hasOneUse()");
+ }
+ }
+
+ // If there are node predicates for this, emit the calls.
+ for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i)
+ emitCheck(N->getPredicateFns()[i] + "(" + RootName + ".getNode())");
+
+ // 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)->getPredicateFns().empty()) {
+ if (IntInit *II = dynamic_cast<IntInit*>(N->getChild(1)->getLeafValue())) {
+ if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits.
+ emitInit("SDValue " + RootName + "0" + " = " +
+ RootName + ".getOperand(" + utostr(0) + ");");
+ emitInit("SDValue " + RootName + "1" + " = " +
+ RootName + ".getOperand(" + utostr(1) + ");");
+
+ unsigned NTmp = TmpNo++;
+ emitCode("ConstantSDNode *Tmp" + utostr(NTmp) +
+ " = dyn_cast<ConstantSDNode>(" + RootName + "1);");
+ emitCheck("Tmp" + utostr(NTmp));
+ const char *MaskPredicate = N->getOperator()->getName() == "or"
+ ? "CheckOrMask(" : "CheckAndMask(";
+ emitCheck(MaskPredicate + RootName + "0, Tmp" + utostr(NTmp) +
+ ", INT64_C(" + itostr(II->getValue()) + "))");
+
+ EmitChildMatchCode(N->getChild(0), N, RootName + utostr(0), RootName,
+ ChainSuffix + utostr(0), FoundChain);
+ return;
+ }
+ }
+ }
+
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) {
+ emitInit("SDValue " + RootName + utostr(OpNo) + " = " +
+ RootName + ".getOperand(" +utostr(OpNo) + ");");
+
+ EmitChildMatchCode(N->getChild(i), N, RootName + utostr(OpNo), RootName,
+ ChainSuffix + utostr(OpNo), FoundChain);
+ }
+
+ // Handle cases when root is a complex pattern.
+ const ComplexPattern *CP;
+ if (isRoot && N->isLeaf() && (CP = NodeGetComplexPattern(N, CGP))) {
+ std::string Fn = CP->getSelectFunc();
+ unsigned NumOps = CP->getNumOperands();
+ for (unsigned i = 0; i < NumOps; ++i) {
+ emitDecl("CPTmp" + RootName + "_" + utostr(i));
+ emitCode("SDValue CPTmp" + RootName + "_" + utostr(i) + ";");
+ }
+ if (CP->hasProperty(SDNPHasChain)) {
+ emitDecl("CPInChain");
+ emitDecl("Chain" + ChainSuffix);
+ emitCode("SDValue CPInChain;");
+ emitCode("SDValue Chain" + ChainSuffix + ";");
+ }
+
+ std::string Code = Fn + "(" + RootName + ", " + RootName;
+ for (unsigned i = 0; i < NumOps; i++)
+ Code += ", CPTmp" + RootName + "_" + 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 &ParentRootName,
+ const std::string &ChainSuffix, bool &FoundChain) {
+ if (!Child->isLeaf()) {
+ // If it's not a leaf, recursively match.
+ const SDNodeInfo &CInfo = CGP.getSDNodeInfo(Child->getOperator());
+ emitCheck(RootName + ".getOpcode() == " +
+ CInfo.getEnumName());
+ EmitMatchCode(Child, Parent, RootName, ChainSuffix, FoundChain);
+ bool HasChain = false;
+ if (NodeHasProperty(Child, SDNPHasChain, CGP)) {
+ HasChain = true;
+ FoldedChains.push_back(std::make_pair(RootName, CInfo.getNumResults()));
+ }
+ if (NodeHasProperty(Child, SDNPOutFlag, CGP)) {
+ assert(FoldedFlag.first == "" && FoldedFlag.second == 0 &&
+ "Pattern folded multiple nodes which produce flags?");
+ FoldedFlag = std::make_pair(RootName,
+ CInfo.getNumResults() + (unsigned)HasChain);
+ }
+ } 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, CGP);
+ std::string Fn = CP->getSelectFunc();
+ unsigned NumOps = CP->getNumOperands();
+ for (unsigned i = 0; i < NumOps; ++i) {
+ emitDecl("CPTmp" + RootName + "_" + utostr(i));
+ emitCode("SDValue CPTmp" + RootName + "_" + utostr(i) + ";");
+ }
+ if (CP->hasProperty(SDNPHasChain)) {
+ const SDNodeInfo &PInfo = CGP.getSDNodeInfo(Parent->getOperator());
+ FoldedChains.push_back(std::make_pair("CPInChain",
+ PInfo.getNumResults()));
+ ChainName = "Chain" + ChainSuffix;
+ emitDecl("CPInChain");
+ emitDecl(ChainName);
+ emitCode("SDValue CPInChain;");
+ emitCode("SDValue " + ChainName + ";");
+ }
+
+ std::string Code = Fn + "(";
+ if (CP->hasAttribute(CPAttrParentAsRoot)) {
+ Code += ParentRootName + ", ";
+ } else {
+ Code += "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" + RootName + "_" + 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 are node predicates for this, emit the calls.
+ for (unsigned i = 0, e = Child->getPredicateFns().size(); i != e; ++i)
+ emitCheck(Child->getPredicateFns()[i] + "(" + RootName +
+ ".getNode())");
+ } else if (IntInit *II =
+ dynamic_cast<IntInit*>(Child->getLeafValue())) {
+ unsigned NTmp = TmpNo++;
+ emitCode("ConstantSDNode *Tmp"+ utostr(NTmp) +
+ " = dyn_cast<ConstantSDNode>("+
+ RootName + ");");
+ emitCheck("Tmp" + utostr(NTmp));
+ unsigned CTmp = TmpNo++;
+ emitCode("int64_t CN"+ utostr(CTmp) +
+ " = Tmp" + utostr(NTmp) + "->getSExtValue();");
+ emitCheck("CN" + utostr(CTmp) + " == "
+ "INT64_C(" +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, std::vector<Record*> DstRegs,
+ 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()) {
+ const std::string &VarName = N->getName();
+ std::string Val = VariableMap[VarName];
+ bool ModifiedVal = false;
+ if (Val.empty()) {
+ cerr << "Variable '" << VarName << " referenced but not defined "
+ << "and not caught earlier!\n";
+ abort();
+ }
+ 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;
+ std::string TmpVar = "Tmp" + utostr(ResNo);
+ 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("SDValue " + TmpVar +
+ " = CurDAG->getTargetConstant(((" + CastType +
+ ") cast<ConstantSDNode>(" + Val + ")->getZExtValue()), " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this
+ // value if used multiple times by this pattern result.
+ Val = TmpVar;
+ ModifiedVal = true;
+ NodeOps.push_back(Val);
+ } else if (!N->isLeaf() && N->getOperator()->getName() == "fpimm") {
+ assert(N->getExtTypes().size() == 1 && "Multiple types not handled!");
+ std::string TmpVar = "Tmp" + utostr(ResNo);
+ emitCode("SDValue " + TmpVar +
+ " = CurDAG->getTargetConstantFP(*cast<ConstantFPSDNode>(" +
+ Val + ")->getConstantFPValue(), cast<ConstantFPSDNode>(" +
+ Val + ")->getValueType(0));");
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this
+ // value if used multiple times by this pattern result.
+ Val = TmpVar;
+ ModifiedVal = true;
+ NodeOps.push_back(Val);
+ } else if (!N->isLeaf() && N->getOperator()->getName() == "texternalsym"){
+ Record *Op = OperatorMap[N->getName()];
+ // Transform ExternalSymbol to TargetExternalSymbol
+ if (Op && Op->getName() == "externalsym") {
+ std::string TmpVar = "Tmp"+utostr(ResNo);
+ emitCode("SDValue " + TmpVar + " = CurDAG->getTarget"
+ "ExternalSymbol(cast<ExternalSymbolSDNode>(" +
+ Val + ")->getSymbol(), " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select
+ // this value if used multiple times by this pattern result.
+ Val = TmpVar;
+ ModifiedVal = true;
+ }
+ 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")) {
+ std::string TmpVar = "Tmp" + utostr(ResNo);
+ emitCode("SDValue " + TmpVar + " = CurDAG->getTarget"
+ "GlobalAddress(cast<GlobalAddressSDNode>(" + Val +
+ ")->getGlobal(), " + getEnumName(N->getTypeNum(0)) +
+ ");");
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select
+ // this value if used multiple times by this pattern result.
+ Val = TmpVar;
+ ModifiedVal = true;
+ }
+ NodeOps.push_back(Val);
+ } else if (!N->isLeaf()
+ && (N->getOperator()->getName() == "texternalsym"
+ || N->getOperator()->getName() == "tconstpool")) {
+ // Do not rewrite the variable name, since we don't generate a new
+ // temporary.
+ NodeOps.push_back(Val);
+ } else if (N->isLeaf() && (CP = NodeGetComplexPattern(N, CGP))) {
+ for (unsigned i = 0; i < CP->getNumOperands(); ++i) {
+ NodeOps.push_back("CPTmp" + Val + "_" + 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) {
+ if (isRoot && N->isLeaf()) {
+ emitCode("ReplaceUses(N, " + Val + ");");
+ emitCode("return NULL;");
+ }
+ }
+ NodeOps.push_back(Val);
+ }
+
+ if (ModifiedVal) {
+ VariableMap[VarName] = 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("SDValue Tmp" + utostr(ResNo) + " = CurDAG->getRegister(" +
+ getQualifiedName(DI->getDef()) + ", " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ return NodeOps;
+ } else if (DI->getDef()->getName() == "zero_reg") {
+ emitCode("SDValue Tmp" + utostr(ResNo) +
+ " = CurDAG->getRegister(0, " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ return NodeOps;
+ } else if (DI->getDef()->isSubClassOf("RegisterClass")) {
+ // Handle a reference to a register class. This is used
+ // in COPY_TO_SUBREG instructions.
+ emitCode("SDValue Tmp" + utostr(ResNo) +
+ " = CurDAG->getTargetConstant(" +
+ getQualifiedName(DI->getDef()) + "RegClassID, " +
+ "MVT::i32);");
+ 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("SDValue Tmp" + utostr(ResNo) +
+ " = CurDAG->getTargetConstant(0x" + itohexstr(II->getValue()) +
+ "ULL, " + 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 = CGP.getTargetInfo();
+ CodeGenInstruction &II = CGT.getInstruction(Op->getName());
+ const DAGInstruction &Inst = CGP.getInstruction(Op);
+ const TreePattern *InstPat = Inst.getPattern();
+ // FIXME: Assume actual pattern comes before "implicit".
+ TreePatternNode *InstPatNode =
+ isRoot ? (InstPat ? InstPat->getTree(0) : Pattern)
+ : (InstPat ? InstPat->getTree(0) : NULL);
+ if (InstPatNode && !InstPatNode->isLeaf() &&
+ InstPatNode->getOperator()->getName() == "set") {
+ InstPatNode = InstPatNode->getChild(InstPatNode->getNumChildren()-1);
+ }
+ bool IsVariadic = isRoot && II.isVariadic;
+ // FIXME: fix how we deal with physical register operands.
+ bool HasImpInputs = isRoot && Inst.getNumImpOperands() > 0;
+ bool HasImpResults = isRoot && DstRegs.size() > 0;
+ bool NodeHasOptInFlag = isRoot &&
+ PatternHasProperty(Pattern, SDNPOptInFlag, CGP);
+ bool NodeHasInFlag = isRoot &&
+ PatternHasProperty(Pattern, SDNPInFlag, CGP);
+ bool NodeHasOutFlag = isRoot &&
+ PatternHasProperty(Pattern, SDNPOutFlag, CGP);
+ bool NodeHasChain = InstPatNode &&
+ PatternHasProperty(InstPatNode, SDNPHasChain, CGP);
+ bool InputHasChain = isRoot &&
+ NodeHasProperty(Pattern, SDNPHasChain, CGP);
+ unsigned NumResults = Inst.getNumResults();
+ unsigned NumDstRegs = HasImpResults ? DstRegs.size() : 0;
+
+ // Record output varargs info.
+ OutputIsVariadic = IsVariadic;
+
+ if (NodeHasOptInFlag) {
+ emitCode("bool HasInFlag = "
+ "(N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag);");
+ }
+ if (IsVariadic)
+ emitCode("SmallVector<SDValue, 8> Ops" + utostr(OpcNo) + ";");
+
+ // How many results is this pattern expected to produce?
+ unsigned NumPatResults = 0;
+ for (unsigned i = 0, e = Pattern->getExtTypes().size(); i != e; i++) {
+ MVT::SimpleValueType VT = Pattern->getTypeNum(i);
+ if (VT != MVT::isVoid && VT != MVT::Flag)
+ NumPatResults++;
+ }
+
+ 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<SDValue, 8> InChains;");
+ for (unsigned i = 0, e = OrigChains.size(); i < e; ++i) {
+ emitCode("if (" + OrigChains[i].first + ".getNode() != " +
+ OrigChains[i].second + ".getNode()) {");
+ emitCode(" InChains.push_back(" + OrigChains[i].first + ");");
+ emitCode("}");
+ }
+ emitCode("InChains.push_back(" + ChainName + ");");
+ emitCode(ChainName + " = CurDAG->getNode(ISD::TokenFactor, "
+ "N.getDebugLoc(), MVT::Other, "
+ "&InChains[0], InChains.size());");
+ if (GenDebug) {
+ emitCode("CurDAG->setSubgraphColor(" + ChainName +".getNode(), \"yellow\");");
+ emitCode("CurDAG->setSubgraphColor(" + ChainName +".getNode(), \"black\");");
+ }
+ }
+
+ // 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;
+ for (unsigned ChildNo = 0, InstOpNo = NumResults;
+ InstOpNo != II.OperandList.size(); ++InstOpNo) {
+ std::vector<std::string> Ops;
+
+ // Determine what to emit for this operand.
+ Record *OperandNode = II.OperandList[InstOpNo].Rec;
+ if ((OperandNode->isSubClassOf("PredicateOperand") ||
+ OperandNode->isSubClassOf("OptionalDefOperand")) &&
+ !CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) {
+ // This is a predicate or optional def operand; emit the
+ // 'default ops' operands.
+ const DAGDefaultOperand &DefaultOp =
+ CGP.getDefaultOperand(II.OperandList[InstOpNo].Rec);
+ for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i) {
+ Ops = EmitResultCode(DefaultOp.DefaultOps[i], DstRegs,
+ InFlagDecled, ResNodeDecled);
+ AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
+ }
+ } else {
+ // Otherwise this is a normal operand or a predicate operand without
+ // 'execute always'; emit it.
+ Ops = EmitResultCode(N->getChild(ChildNo), DstRegs,
+ InFlagDecled, ResNodeDecled);
+ AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
+ ++ChildNo;
+ }
+ }
+
+ // Emit all the chain and CopyToReg stuff.
+ bool ChainEmitted = NodeHasChain;
+ if (NodeHasInFlag || HasImpInputs)
+ EmitInFlagSelectCode(Pattern, "N", ChainEmitted,
+ InFlagDecled, ResNodeDecled, true);
+ if (NodeHasOptInFlag || NodeHasInFlag || HasImpInputs) {
+ if (!InFlagDecled) {
+ emitCode("SDValue InFlag(0, 0);");
+ InFlagDecled = true;
+ }
+ if (NodeHasOptInFlag) {
+ emitCode("if (HasInFlag) {");
+ emitCode(" InFlag = N.getOperand(N.getNumOperands()-1);");
+ emitCode("}");
+ }
+ }
+
+ unsigned ResNo = TmpNo++;
+
+ unsigned OpsNo = OpcNo;
+ std::string CodePrefix;
+ bool ChainAssignmentNeeded = NodeHasChain && !isRoot;
+ std::deque<std::string> After;
+ std::string NodeName;
+ if (!isRoot) {
+ NodeName = "Tmp" + utostr(ResNo);
+ CodePrefix = "SDValue " + NodeName + "(";
+ } else {
+ NodeName = "ResNode";
+ if (!ResNodeDecled) {
+ CodePrefix = "SDNode *" + NodeName + " = ";
+ ResNodeDecled = true;
+ } else
+ CodePrefix = NodeName + " = ";
+ }
+
+ std::string Code = "Opc" + utostr(OpcNo);
+
+ if (!isRoot || (InputHasChain && !NodeHasChain))
+ // For call to "getTargetNode()".
+ Code += ", N.getDebugLoc()";
+
+ 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)));
+ }
+ // Add types for implicit results in physical registers, scheduler will
+ // care of adding copyfromreg nodes.
+ for (unsigned i = 0; i < NumDstRegs; i++) {
+ Record *RR = DstRegs[i];
+ if (RR->isSubClassOf("Register")) {
+ MVT::SimpleValueType RVT = getRegisterValueType(RR, CGT);
+ Code += ", " + getEnumName(RVT);
+ }
+ }
+ if (NodeHasChain)
+ Code += ", MVT::Other";
+ if (NodeHasOutFlag)
+ Code += ", MVT::Flag";
+
+ // Inputs.
+ if (IsVariadic) {
+ for (unsigned i = 0, e = AllOps.size(); i != e; ++i)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");");
+ AllOps.clear();
+
+ // 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 = NumInputRootOps + " + utostr(NodeHasChain) +
+ ", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {");
+
+ emitCode(" Ops" + utostr(OpsNo) + ".push_back(N.getOperand(i));");
+ emitCode("}");
+ }
+
+ // Generate MemOperandSDNodes nodes for each memory accesses covered by
+ // this pattern.
+ if (II.mayLoad | II.mayStore) {
+ std::vector<std::string>::const_iterator mi, mie;
+ for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) {
+ std::string LSIName = "LSI_" + *mi;
+ emitCode("SDValue " + LSIName + " = "
+ "CurDAG->getMemOperand(cast<MemSDNode>(" +
+ *mi + ")->getMemOperand());");
+ if (GenDebug) {
+ emitCode("CurDAG->setSubgraphColor(" + LSIName +".getNode(), \"yellow\");");
+ emitCode("CurDAG->setSubgraphColor(" + LSIName +".getNode(), \"black\");");
+ }
+ if (IsVariadic)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + LSIName + ");");
+ else
+ AllOps.push_back(LSIName);
+ }
+ }
+
+ if (NodeHasChain) {
+ if (IsVariadic)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + ChainName + ");");
+ else
+ AllOps.push_back(ChainName);
+ }
+
+ if (IsVariadic) {
+ 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 = "SDValue 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";
+
+ std::vector<std::string> ReplaceFroms;
+ std::vector<std::string> ReplaceTos;
+ if (!isRoot) {
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ } else {
+
+ if (NodeHasOutFlag) {
+ if (!InFlagDecled) {
+ After.push_back("SDValue InFlag(ResNode, " +
+ utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) +
+ ");");
+ InFlagDecled = true;
+ } else
+ After.push_back("InFlag = SDValue(ResNode, " +
+ utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) +
+ ");");
+ }
+
+ for (unsigned j = 0, e = FoldedChains.size(); j < e; j++) {
+ ReplaceFroms.push_back("SDValue(" +
+ FoldedChains[j].first + ".getNode(), " +
+ utostr(FoldedChains[j].second) +
+ ")");
+ ReplaceTos.push_back("SDValue(ResNode, " +
+ utostr(NumResults+NumDstRegs) + ")");
+ }
+
+ if (NodeHasOutFlag) {
+ if (FoldedFlag.first != "") {
+ ReplaceFroms.push_back("SDValue(" + FoldedFlag.first + ".getNode(), " +
+ utostr(FoldedFlag.second) + ")");
+ ReplaceTos.push_back("InFlag");
+ } else {
+ assert(NodeHasProperty(Pattern, SDNPOutFlag, CGP));
+ ReplaceFroms.push_back("SDValue(N.getNode(), " +
+ utostr(NumPatResults + (unsigned)InputHasChain)
+ + ")");
+ ReplaceTos.push_back("InFlag");
+ }
+ }
+
+ if (!ReplaceFroms.empty() && InputHasChain) {
+ ReplaceFroms.push_back("SDValue(N.getNode(), " +
+ utostr(NumPatResults) + ")");
+ ReplaceTos.push_back("SDValue(" + ChainName + ".getNode(), " +
+ ChainName + ".getResNo()" + ")");
+ ChainAssignmentNeeded |= NodeHasChain;
+ }
+
+ // 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) {
+ ReplaceFroms.push_back("SDValue(N.getNode(), " +
+ utostr(NumPatResults+1) +
+ ")");
+ ReplaceTos.push_back("SDValue(ResNode, N.getResNo()-1)");
+ }
+ ReplaceFroms.push_back("SDValue(N.getNode(), " +
+ utostr(NumPatResults) + ")");
+ ReplaceTos.push_back(ChainName);
+ }
+ }
+
+ if (ChainAssignmentNeeded) {
+ // Remember which op produces the chain.
+ std::string ChainAssign;
+ if (!isRoot)
+ ChainAssign = ChainName + " = SDValue(" + NodeName +
+ ".getNode(), " + utostr(NumResults+NumDstRegs) + ");";
+ else
+ ChainAssign = ChainName + " = SDValue(" + NodeName +
+ ", " + utostr(NumResults+NumDstRegs) + ");";
+
+ After.push_front(ChainAssign);
+ }
+
+ if (ReplaceFroms.size() == 1) {
+ After.push_back("ReplaceUses(" + ReplaceFroms[0] + ", " +
+ ReplaceTos[0] + ");");
+ } else if (!ReplaceFroms.empty()) {
+ After.push_back("const SDValue Froms[] = {");
+ for (unsigned i = 0, e = ReplaceFroms.size(); i != e; ++i)
+ After.push_back(" " + ReplaceFroms[i] + (i + 1 != e ? "," : ""));
+ After.push_back("};");
+ After.push_back("const SDValue Tos[] = {");
+ for (unsigned i = 0, e = ReplaceFroms.size(); i != e; ++i)
+ After.push_back(" " + ReplaceTos[i] + (i + 1 != e ? "," : ""));
+ After.push_back("};");
+ After.push_back("ReplaceUses(Froms, Tos, " +
+ itostr(ReplaceFroms.size()) + ");");
+ }
+
+ // We prefer to use SelectNodeTo since it avoids allocation when
+ // possible and it avoids CSE map recalculation for the node's
+ // users, however it's tricky to use in a non-root context.
+ //
+ // We also don't use if the pattern replacement is being used to
+ // jettison a chain result, since morphing the node in place
+ // would leave users of the chain dangling.
+ //
+ if (!isRoot || (InputHasChain && !NodeHasChain)) {
+ Code = "CurDAG->getTargetNode(" + Code;
+ } else {
+ Code = "CurDAG->SelectNodeTo(N.getNode(), " + Code;
+ }
+ if (isRoot) {
+ if (After.empty())
+ CodePrefix = "return ";
+ else
+ After.push_back("return ResNode;");
+ }
+
+ emitCode(CodePrefix + Code + ");");
+
+ if (GenDebug) {
+ if (!isRoot) {
+ emitCode("CurDAG->setSubgraphColor(" + NodeName +".getNode(), \"yellow\");");
+ emitCode("CurDAG->setSubgraphColor(" + NodeName +".getNode(), \"black\");");
+ }
+ else {
+ emitCode("CurDAG->setSubgraphColor(" + NodeName +", \"yellow\");");
+ emitCode("CurDAG->setSubgraphColor(" + NodeName +", \"black\");");
+ }
+ }
+
+ for (unsigned i = 0, e = After.size(); i != e; ++i)
+ emitCode(After[i]);
+
+ return NodeOps;
+ }
+ 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), DstRegs, InFlagDecled,
+ ResNodeDecled, true);
+ unsigned ResNo = TmpNo++;
+ emitCode("SDValue Tmp" + utostr(ResNo) + " = Transform_" + Op->getName()
+ + "(" + Ops.back() + ".getNode());");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ if (isRoot)
+ emitCode("return Tmp" + utostr(ResNo) + ".getNode();");
+ return NodeOps;
+ }
+
+ 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 + ".getNode()->getValueType(0) == " +
+ getName(Pat->getTypeNum(0)));
+ return true;
+ }
+
+ unsigned OpNo =
+ (unsigned) NodeHasProperty(Pat, SDNPHasChain, CGP);
+ 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 = CGP.getTargetInfo();
+ unsigned OpNo =
+ (unsigned) NodeHasProperty(N, SDNPHasChain, CGP);
+ bool HasInFlag = NodeHasProperty(N, SDNPInFlag, CGP);
+ 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::SimpleValueType RVT = getRegisterValueType(RR, T);
+ if (RVT == MVT::Flag) {
+ if (!InFlagDecled) {
+ emitCode("SDValue InFlag = " + RootName + utostr(OpNo) + ";");
+ InFlagDecled = true;
+ } else
+ emitCode("InFlag = " + RootName + utostr(OpNo) + ";");
+ } else {
+ if (!ChainEmitted) {
+ emitCode("SDValue Chain = CurDAG->getEntryNode();");
+ ChainName = "Chain";
+ ChainEmitted = true;
+ }
+ if (!InFlagDecled) {
+ emitCode("SDValue InFlag(0, 0);");
+ InFlagDecled = true;
+ }
+ std::string Decl = (!ResNodeDecled) ? "SDNode *" : "";
+ emitCode(Decl + "ResNode = CurDAG->getCopyToReg(" + ChainName +
+ ", " + RootName + ".getDebugLoc()" +
+ ", " + getQualifiedName(RR) +
+ ", " + RootName + utostr(OpNo) + ", InFlag).getNode();");
+ ResNodeDecled = true;
+ emitCode(ChainName + " = SDValue(ResNode, 0);");
+ emitCode("InFlag = SDValue(ResNode, 1);");
+ }
+ }
+ }
+ }
+ }
+
+ if (HasInFlag) {
+ if (!InFlagDecled) {
+ emitCode("SDValue InFlag = " + RootName +
+ ".getOperand(" + utostr(OpNo) + ");");
+ InFlagDecled = true;
+ } else
+ emitCode("InFlag = " + RootName +
+ ".getOperand(" + utostr(OpNo) + ");");
+ }
+ }
+};
+
+/// 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(const 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,
+ bool &OutputIsVariadic,
+ unsigned &NumInputRootOps) {
+ OutputIsVariadic = false;
+ NumInputRootOps = 0;
+
+ PatternCodeEmitter Emitter(CGP, Pattern.getPredicateCheck(),
+ Pattern.getSrcPattern(), Pattern.getDstPattern(),
+ GeneratedCode, GeneratedDecl,
+ TargetOpcodes, TargetVTs,
+ OutputIsVariadic, NumInputRootOps);
+
+ // 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 = *CGP.pf_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(), Pattern.getDstRegs(),
+ 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<const 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<const 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<const 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) {
+ const 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(), CGP) + AddedComplexity
+ << " cost = "
+ << getResultPatternCost(Pattern.getDstPattern(), CGP)
+ << " size = "
+ << getResultPatternSize(Pattern.getDstPattern(), CGP) << "\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) {
+ const 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(), CGP) + AddedComplexity
+ << " cost = "
+ << getResultPatternCost(Pattern.getDstPattern(), CGP)
+ << " size = "
+ << getResultPatternSize(Pattern.getDstPattern(), CGP) << "\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 the 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 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) {
+ const CodeGenTarget &Target = CGP.getTargetInfo();
+
+ // Get the namespace to insert instructions into.
+ std::string InstNS = Target.getInstNamespace();
+ if (!InstNS.empty()) InstNS += "::";
+
+ // Group the patterns by their top-level opcodes.
+ std::map<std::string, std::vector<const PatternToMatch*> > PatternsByOpcode;
+ // All unique target node emission functions.
+ std::map<std::string, unsigned> EmitFunctions;
+ for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(),
+ E = CGP.ptm_end(); I != E; ++I) {
+ const PatternToMatch &Pattern = *I;
+
+ TreePatternNode *Node = Pattern.getSrcPattern();
+ if (!Node->isLeaf()) {
+ PatternsByOpcode[getOpcodeName(Node->getOperator(), CGP)].
+ push_back(&Pattern);
+ } else {
+ const ComplexPattern *CP;
+ if (dynamic_cast<IntInit*>(Node->getLeafValue())) {
+ PatternsByOpcode[getOpcodeName(CGP.getSDNodeNamed("imm"), CGP)].
+ push_back(&Pattern);
+ } else if ((CP = NodeGetComplexPattern(Node, CGP))) {
+ std::vector<Record*> OpNodes = CP->getRootNodes();
+ for (unsigned j = 0, e = OpNodes.size(); j != e; j++) {
+ PatternsByOpcode[getOpcodeName(OpNodes[j], CGP)]
+ .insert(PatternsByOpcode[getOpcodeName(OpNodes[j], CGP)].begin(),
+ &Pattern);
+ }
+ } else {
+ cerr << "Unrecognized opcode '";
+ Node->dump();
+ cerr << "' on tree pattern '";
+ cerr << Pattern.getDstPattern()->getOperator()->getName() << "'!\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<const PatternToMatch*> >::iterator
+ PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end();
+ PBOI != E; ++PBOI) {
+ const std::string &OpName = PBOI->first;
+ std::vector<const PatternToMatch*> &PatternsOfOp = PBOI->second;
+ assert(!PatternsOfOp.empty() && "No patterns but map has entry?");
+
+ // Split them into groups by type.
+ std::map<MVT::SimpleValueType,
+ std::vector<const PatternToMatch*> > PatternsByType;
+ for (unsigned i = 0, e = PatternsOfOp.size(); i != e; ++i) {
+ const PatternToMatch *Pat = PatternsOfOp[i];
+ TreePatternNode *SrcPat = Pat->getSrcPattern();
+ PatternsByType[SrcPat->getTypeNum(0)].push_back(Pat);
+ }
+
+ for (std::map<MVT::SimpleValueType,
+ std::vector<const PatternToMatch*> >::iterator
+ II = PatternsByType.begin(), EE = PatternsByType.end(); II != EE;
+ ++II) {
+ MVT::SimpleValueType OpVT = II->first;
+ std::vector<const PatternToMatch*> &Patterns = II->second;
+ typedef std::pair<unsigned, std::string> CodeLine;
+ typedef std::vector<CodeLine> CodeList;
+ typedef CodeList::iterator CodeListI;
+
+ std::vector<std::pair<const PatternToMatch*, CodeList> > CodeForPatterns;
+ std::vector<std::vector<std::string> > PatternOpcodes;
+ std::vector<std::vector<std::string> > PatternVTs;
+ std::vector<std::set<std::string> > PatternDecls;
+ std::vector<bool> OutputIsVariadicFlags;
+ std::vector<unsigned> NumInputRootOpsCounts;
+ 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;
+ bool OutputIsVariadic;
+ unsigned NumInputRootOps;
+ GenerateCodeForPattern(*Patterns[i], GeneratedCode, GeneratedDecl,
+ TargetOpcodes, TargetVTs,
+ OutputIsVariadic, NumInputRootOps);
+ CodeForPatterns.push_back(std::make_pair(Patterns[i], GeneratedCode));
+ PatternDecls.push_back(GeneratedDecl);
+ PatternOpcodes.push_back(TargetOpcodes);
+ PatternVTs.push_back(TargetVTs);
+ OutputIsVariadicFlags.push_back(OutputIsVariadic);
+ NumInputRootOpsCounts.push_back(NumInputRootOps);
+ }
+
+ // 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];
+ bool OutputIsVariadic = OutputIsVariadicFlags[i];
+ unsigned NumInputRootOps = NumInputRootOpsCounts[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 SDValue &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 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 += ", SDValue &" + Name;
+ CallerCode += ", " + Name;
+ }
+
+ if (OutputIsVariadic) {
+ CalleeCode += ", unsigned NumInputRootOps";
+ CallerCode += ", " + utostr(NumInputRootOps);
+ }
+
+ 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.
+ if (GenDebug) {
+ GeneratedCode.push_back(std::make_pair(0, "CurDAG->setSubgraphColor(N.getNode(), \"red\");"));
+ }
+ CallerCode = "SDNode *Result = Emit_" + utostr(EmitFuncNum) + CallerCode;
+ GeneratedCode.push_back(std::make_pair(3, CallerCode));
+ if (GenDebug) {
+ GeneratedCode.push_back(std::make_pair(0, "if(Result) {"));
+ GeneratedCode.push_back(std::make_pair(0, " CurDAG->setSubgraphColor(Result, \"yellow\");"));
+ GeneratedCode.push_back(std::make_pair(0, " CurDAG->setSubgraphColor(Result, \"black\");"));
+ GeneratedCode.push_back(std::make_pair(0, "}"));
+ //GeneratedCode.push_back(std::make_pair(0, "CurDAG->setSubgraphColor(N.getNode(), \"black\");"));
+ }
+ GeneratedCode.push_back(std::make_pair(0, "return Result;"));
+ }
+
+ // Print function.
+ std::string OpVTStr;
+ if (OpVT == MVT::iPTR) {
+ OpVTStr = "_iPTR";
+ } else if (OpVT == MVT::iPTRAny) {
+ OpVTStr = "_iPTRAny";
+ } 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);
+
+ // 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(CodeForPatterns.begin(), CodeForPatterns.end(),
+ PatternSortingPredicate(CGP));
+
+ // 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);
+ }
+ }
+
+ // 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());
+
+ OS << "SDNode *Select_" << getLegalCName(OpName)
+ << OpVTStr << "(const SDValue &N) {\n";
+
+ // 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 << "\n";
+ if (OpName != "ISD::INTRINSIC_W_CHAIN" &&
+ OpName != "ISD::INTRINSIC_WO_CHAIN" &&
+ OpName != "ISD::INTRINSIC_VOID")
+ OS << " CannotYetSelect(N);\n";
+ else
+ OS << " CannotYetSelectIntrinsic(N);\n";
+
+ OS << " return NULL;\n";
+ }
+ OS << "}\n\n";
+ }
+ }
+
+ // Emit boilerplate.
+ OS << "SDNode *Select_INLINEASM(SDValue N) {\n"
+ << " std::vector<SDValue> Ops(N.getNode()->op_begin(), N.getNode()->op_end());\n"
+ << " SelectInlineAsmMemoryOperands(Ops);\n\n"
+
+ << " std::vector<MVT> VTs;\n"
+ << " VTs.push_back(MVT::Other);\n"
+ << " VTs.push_back(MVT::Flag);\n"
+ << " SDValue New = CurDAG->getNode(ISD::INLINEASM, N.getDebugLoc(), "
+ "VTs, &Ops[0], Ops.size());\n"
+ << " return New.getNode();\n"
+ << "}\n\n";
+
+ OS << "SDNode *Select_UNDEF(const SDValue &N) {\n"
+ << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::IMPLICIT_DEF,\n"
+ << " N.getValueType());\n"
+ << "}\n\n";
+
+ OS << "SDNode *Select_DBG_LABEL(const SDValue &N) {\n"
+ << " SDValue Chain = N.getOperand(0);\n"
+ << " unsigned C = cast<LabelSDNode>(N)->getLabelID();\n"
+ << " SDValue Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n"
+ << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::DBG_LABEL,\n"
+ << " MVT::Other, Tmp, Chain);\n"
+ << "}\n\n";
+
+ OS << "SDNode *Select_EH_LABEL(const SDValue &N) {\n"
+ << " SDValue Chain = N.getOperand(0);\n"
+ << " unsigned C = cast<LabelSDNode>(N)->getLabelID();\n"
+ << " SDValue Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n"
+ << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::EH_LABEL,\n"
+ << " MVT::Other, Tmp, Chain);\n"
+ << "}\n\n";
+
+ OS << "SDNode *Select_DECLARE(const SDValue &N) {\n"
+ << " SDValue Chain = N.getOperand(0);\n"
+ << " SDValue N1 = N.getOperand(1);\n"
+ << " SDValue N2 = N.getOperand(2);\n"
+ << " if (!isa<FrameIndexSDNode>(N1) || !isa<GlobalAddressSDNode>(N2)) {\n"
+ << " CannotYetSelect(N);\n"
+ << " }\n"
+ << " int FI = cast<FrameIndexSDNode>(N1)->getIndex();\n"
+ << " GlobalValue *GV = cast<GlobalAddressSDNode>(N2)->getGlobal();\n"
+ << " SDValue Tmp1 = "
+ << "CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());\n"
+ << " SDValue Tmp2 = "
+ << "CurDAG->getTargetGlobalAddress(GV, TLI.getPointerTy());\n"
+ << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::DECLARE,\n"
+ << " MVT::Other, Tmp1, Tmp2, Chain);\n"
+ << "}\n\n";
+
+ OS << "// The main instruction selector code.\n"
+ << "SDNode *SelectCode(SDValue N) {\n"
+ << " MVT::SimpleValueType NVT = N.getNode()->getValueType(0).getSimpleVT();\n"
+ << " switch (N.getOpcode()) {\n"
+ << " default:\n"
+ << " assert(!N.isMachineOpcode() && \"Node already selected!\");\n"
+ << " break;\n"
+ << " case ISD::EntryToken: // These nodes remain the same.\n"
+ << " case ISD::MEMOPERAND:\n"
+ << " case ISD::BasicBlock:\n"
+ << " case ISD::Register:\n"
+ << " case ISD::HANDLENODE:\n"
+ << " case ISD::TargetConstant:\n"
+ << " case ISD::TargetConstantFP:\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"
+ << " case ISD::TokenFactor:\n"
+ << " case ISD::CopyFromReg:\n"
+ << " case ISD::CopyToReg: {\n"
+ << " return NULL;\n"
+ << " }\n"
+ << " case ISD::AssertSext:\n"
+ << " case ISD::AssertZext: {\n"
+ << " ReplaceUses(N, N.getOperand(0));\n"
+ << " return NULL;\n"
+ << " }\n"
+ << " case ISD::INLINEASM: return Select_INLINEASM(N);\n"
+ << " case ISD::DBG_LABEL: return Select_DBG_LABEL(N);\n"
+ << " case ISD::EH_LABEL: return Select_EH_LABEL(N);\n"
+ << " case ISD::DECLARE: return Select_DECLARE(N);\n"
+ << " case ISD::UNDEF: return Select_UNDEF(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<const 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 we have only one variant and it's the default, elide the
+ // switch. Marginally faster, and makes MSVC happier.
+ if (OpVTs.size()==1 && OpVTs[0].empty()) {
+ OS << " return Select_" << getLegalCName(OpName) << "(N);\n";
+ OS << " break;\n";
+ OS << " }\n";
+ continue;
+ }
+ // 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 (TLI.getPointerTy() == NVT)\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"
+ << " if (N.getOpcode() != ISD::INTRINSIC_W_CHAIN &&\n"
+ << " N.getOpcode() != ISD::INTRINSIC_WO_CHAIN &&\n"
+ << " N.getOpcode() != ISD::INTRINSIC_VOID) {\n"
+ << " CannotYetSelect(N);\n"
+ << " } else {\n"
+ << " CannotYetSelectIntrinsic(N);\n"
+ << " }\n"
+ << " return NULL;\n"
+ << "}\n\n";
+
+ OS << "void CannotYetSelect(SDValue N) DISABLE_INLINE {\n"
+ << " cerr << \"Cannot yet select: \";\n"
+ << " N.getNode()->dump(CurDAG);\n"
+ << " cerr << '\\n';\n"
+ << " abort();\n"
+ << "}\n\n";
+
+ OS << "void CannotYetSelectIntrinsic(SDValue N) DISABLE_INLINE {\n"
+ << " cerr << \"Cannot yet select: \";\n"
+ << " unsigned iid = cast<ConstantSDNode>(N.getOperand("
+ << "N.getOperand(0).getValueType() == MVT::Other))->getZExtValue();\n"
+ << " cerr << \"intrinsic %\"<< "
+ << "Intrinsic::getName((Intrinsic::ID)iid);\n"
+ << " cerr << '\\n';\n"
+ << " abort();\n"
+ << "}\n\n";
+}
+
+void DAGISelEmitter::run(std::ostream &OS) {
+ EmitSourceFileHeader("DAG Instruction Selector for the " +
+ CGP.getTargetInfo().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 standard, target-independent definitions and methods used\n"
+ << "// by the instruction selector.\n";
+ OS << "#include \"llvm/CodeGen/DAGISelHeader.h\"\n\n";
+
+ EmitNodeTransforms(OS);
+ EmitPredicateFunctions(OS);
+
+ DOUT << "\n\nALL PATTERNS TO MATCH:\n\n";
+ for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end();
+ I != E; ++I) {
+ DOUT << "PATTERN: "; DEBUG(I->getSrcPattern()->dump());
+ DOUT << "\nRESULT: "; DEBUG(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);
+
+}
diff --git a/utils/TableGen/DAGISelEmitter.h b/utils/TableGen/DAGISelEmitter.h
new file mode 100644
index 000000000000..1b9f8bad88cd
--- /dev/null
+++ b/utils/TableGen/DAGISelEmitter.h
@@ -0,0 +1,56 @@
+//===- DAGISelEmitter.h - Generate an instruction selector ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "CodeGenDAGPatterns.h"
+#include <set>
+
+namespace llvm {
+
+/// DAGISelEmitter - The top-level class which coordinates construction
+/// and emission of the instruction selector.
+///
+class DAGISelEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ CodeGenDAGPatterns CGP;
+public:
+ explicit DAGISelEmitter(RecordKeeper &R) : Records(R), CGP(R) {}
+
+ // run - Output the isel, returning true on failure.
+ void run(std::ostream &OS);
+
+
+private:
+ void EmitNodeTransforms(std::ostream &OS);
+ void EmitPredicateFunctions(std::ostream &OS);
+
+ void GenerateCodeForPattern(const 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,
+ bool &OutputIsVariadic,
+ unsigned &NumInputRootOps);
+ void EmitPatterns(std::vector<std::pair<const 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/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
new file mode 100644
index 000000000000..8c60b088627e
--- /dev/null
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -0,0 +1,636 @@
+//===- FastISelEmitter.cpp - Generate an instruction selector -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits code for use by the "fast" instruction
+// selection algorithm. See the comments at the top of
+// lib/CodeGen/SelectionDAG/FastISel.cpp for background.
+//
+// This file scans through the target's tablegen instruction-info files
+// and extracts instructions with obvious-looking patterns, and it emits
+// code to look up these instructions by type and operator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FastISelEmitter.h"
+#include "Record.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/ADT/VectorExtras.h"
+using namespace llvm;
+
+namespace {
+
+/// InstructionMemo - This class holds additional information about an
+/// instruction needed to emit code for it.
+///
+struct InstructionMemo {
+ std::string Name;
+ const CodeGenRegisterClass *RC;
+ unsigned char SubRegNo;
+ std::vector<std::string>* PhysRegs;
+};
+
+/// OperandsSignature - This class holds a description of a list of operand
+/// types. It has utility methods for emitting text based on the operands.
+///
+struct OperandsSignature {
+ std::vector<std::string> Operands;
+
+ bool operator<(const OperandsSignature &O) const {
+ return Operands < O.Operands;
+ }
+
+ bool empty() const { return Operands.empty(); }
+
+ /// initialize - Examine the given pattern and initialize the contents
+ /// of the Operands array accordingly. Return true if all the operands
+ /// are supported, false otherwise.
+ ///
+ bool initialize(TreePatternNode *InstPatNode,
+ const CodeGenTarget &Target,
+ MVT::SimpleValueType VT) {
+ if (!InstPatNode->isLeaf() &&
+ InstPatNode->getOperator()->getName() == "imm") {
+ Operands.push_back("i");
+ return true;
+ }
+ if (!InstPatNode->isLeaf() &&
+ InstPatNode->getOperator()->getName() == "fpimm") {
+ Operands.push_back("f");
+ return true;
+ }
+
+ const CodeGenRegisterClass *DstRC = 0;
+
+ for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Op = InstPatNode->getChild(i);
+ // For now, filter out any operand with a predicate.
+ if (!Op->getPredicateFns().empty())
+ return false;
+ // For now, filter out any operand with multiple values.
+ if (Op->getExtTypes().size() != 1)
+ return false;
+ // For now, all the operands must have the same type.
+ if (Op->getTypeNum(0) != VT)
+ return false;
+ if (!Op->isLeaf()) {
+ if (Op->getOperator()->getName() == "imm") {
+ Operands.push_back("i");
+ continue;
+ }
+ if (Op->getOperator()->getName() == "fpimm") {
+ Operands.push_back("f");
+ continue;
+ }
+ // For now, ignore other non-leaf nodes.
+ return false;
+ }
+ DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue());
+ if (!OpDI)
+ return false;
+ Record *OpLeafRec = OpDI->getDef();
+ // For now, the only other thing we accept is register operands.
+
+ const CodeGenRegisterClass *RC = 0;
+ if (OpLeafRec->isSubClassOf("RegisterClass"))
+ RC = &Target.getRegisterClass(OpLeafRec);
+ else if (OpLeafRec->isSubClassOf("Register"))
+ RC = Target.getRegisterClassForRegister(OpLeafRec);
+ else
+ return false;
+ // For now, require the register operands' register classes to all
+ // be the same.
+ if (!RC)
+ return false;
+ // For now, all the operands must have the same register class.
+ if (DstRC) {
+ if (DstRC != RC)
+ return false;
+ } else
+ DstRC = RC;
+ Operands.push_back("r");
+ }
+ return true;
+ }
+
+ void PrintParameters(std::ostream &OS) const {
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
+ if (Operands[i] == "r") {
+ OS << "unsigned Op" << i;
+ } else if (Operands[i] == "i") {
+ OS << "uint64_t imm" << i;
+ } else if (Operands[i] == "f") {
+ OS << "ConstantFP *f" << i;
+ } else {
+ assert("Unknown operand kind!");
+ abort();
+ }
+ if (i + 1 != e)
+ OS << ", ";
+ }
+ }
+
+ void PrintArguments(std::ostream &OS,
+ const std::vector<std::string>& PR) const {
+ assert(PR.size() == Operands.size());
+ bool PrintedArg = false;
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
+ if (PR[i] != "")
+ // Implicit physical register operand.
+ continue;
+
+ if (PrintedArg)
+ OS << ", ";
+ if (Operands[i] == "r") {
+ OS << "Op" << i;
+ PrintedArg = true;
+ } else if (Operands[i] == "i") {
+ OS << "imm" << i;
+ PrintedArg = true;
+ } else if (Operands[i] == "f") {
+ OS << "f" << i;
+ PrintedArg = true;
+ } else {
+ assert("Unknown operand kind!");
+ abort();
+ }
+ }
+ }
+
+ void PrintArguments(std::ostream &OS) const {
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
+ if (Operands[i] == "r") {
+ OS << "Op" << i;
+ } else if (Operands[i] == "i") {
+ OS << "imm" << i;
+ } else if (Operands[i] == "f") {
+ OS << "f" << i;
+ } else {
+ assert("Unknown operand kind!");
+ abort();
+ }
+ if (i + 1 != e)
+ OS << ", ";
+ }
+ }
+
+
+ void PrintManglingSuffix(std::ostream &OS,
+ const std::vector<std::string>& PR) const {
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
+ if (PR[i] != "")
+ // Implicit physical register operand. e.g. Instruction::Mul expect to
+ // select to a binary op. On x86, mul may take a single operand with
+ // the other operand being implicit. We must emit something that looks
+ // like a binary instruction except for the very inner FastEmitInst_*
+ // call.
+ continue;
+ OS << Operands[i];
+ }
+ }
+
+ void PrintManglingSuffix(std::ostream &OS) const {
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
+ OS << Operands[i];
+ }
+ }
+};
+
+class FastISelMap {
+ typedef std::map<std::string, InstructionMemo> PredMap;
+ typedef std::map<MVT::SimpleValueType, PredMap> RetPredMap;
+ typedef std::map<MVT::SimpleValueType, RetPredMap> TypeRetPredMap;
+ typedef std::map<std::string, TypeRetPredMap> OpcodeTypeRetPredMap;
+ typedef std::map<OperandsSignature, OpcodeTypeRetPredMap> OperandsOpcodeTypeRetPredMap;
+
+ OperandsOpcodeTypeRetPredMap SimplePatterns;
+
+ std::string InstNS;
+
+public:
+ explicit FastISelMap(std::string InstNS);
+
+ void CollectPatterns(CodeGenDAGPatterns &CGP);
+ void PrintClass(std::ostream &OS);
+ void PrintFunctionDefinitions(std::ostream &OS);
+};
+
+}
+
+static std::string getOpcodeName(Record *Op, CodeGenDAGPatterns &CGP) {
+ return CGP.getSDNodeInfo(Op).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;
+}
+
+FastISelMap::FastISelMap(std::string instns)
+ : InstNS(instns) {
+}
+
+void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
+ const CodeGenTarget &Target = CGP.getTargetInfo();
+
+ // Determine the target's namespace name.
+ InstNS = Target.getInstNamespace() + "::";
+ assert(InstNS.size() > 2 && "Can't determine target-specific namespace!");
+
+ // Scan through all the patterns and record the simple ones.
+ for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(),
+ E = CGP.ptm_end(); I != E; ++I) {
+ const PatternToMatch &Pattern = *I;
+
+ // For now, just look at Instructions, so that we don't have to worry
+ // about emitting multiple instructions for a pattern.
+ TreePatternNode *Dst = Pattern.getDstPattern();
+ if (Dst->isLeaf()) continue;
+ Record *Op = Dst->getOperator();
+ if (!Op->isSubClassOf("Instruction"))
+ continue;
+ CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op->getName());
+ if (II.OperandList.empty())
+ continue;
+
+ // For now, ignore multi-instruction patterns.
+ bool MultiInsts = false;
+ for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) {
+ TreePatternNode *ChildOp = Dst->getChild(i);
+ if (ChildOp->isLeaf())
+ continue;
+ if (ChildOp->getOperator()->isSubClassOf("Instruction")) {
+ MultiInsts = true;
+ break;
+ }
+ }
+ if (MultiInsts)
+ continue;
+
+ // For now, ignore instructions where the first operand is not an
+ // output register.
+ const CodeGenRegisterClass *DstRC = 0;
+ unsigned SubRegNo = ~0;
+ if (Op->getName() != "EXTRACT_SUBREG") {
+ Record *Op0Rec = II.OperandList[0].Rec;
+ if (!Op0Rec->isSubClassOf("RegisterClass"))
+ continue;
+ DstRC = &Target.getRegisterClass(Op0Rec);
+ if (!DstRC)
+ continue;
+ } else {
+ SubRegNo = static_cast<IntInit*>(
+ Dst->getChild(1)->getLeafValue())->getValue();
+ }
+
+ // Inspect the pattern.
+ TreePatternNode *InstPatNode = Pattern.getSrcPattern();
+ if (!InstPatNode) continue;
+ if (InstPatNode->isLeaf()) continue;
+
+ Record *InstPatOp = InstPatNode->getOperator();
+ std::string OpcodeName = getOpcodeName(InstPatOp, CGP);
+ MVT::SimpleValueType RetVT = InstPatNode->getTypeNum(0);
+ MVT::SimpleValueType VT = RetVT;
+ if (InstPatNode->getNumChildren())
+ VT = InstPatNode->getChild(0)->getTypeNum(0);
+
+ // For now, filter out instructions which just set a register to
+ // an Operand or an immediate, like MOV32ri.
+ if (InstPatOp->isSubClassOf("Operand"))
+ continue;
+
+ // For now, filter out any instructions with predicates.
+ if (!InstPatNode->getPredicateFns().empty())
+ continue;
+
+ // Check all the operands.
+ OperandsSignature Operands;
+ if (!Operands.initialize(InstPatNode, Target, VT))
+ continue;
+
+ std::vector<std::string>* PhysRegInputs = new std::vector<std::string>();
+ if (!InstPatNode->isLeaf() &&
+ (InstPatNode->getOperator()->getName() == "imm" ||
+ InstPatNode->getOperator()->getName() == "fpimmm"))
+ PhysRegInputs->push_back("");
+ else if (!InstPatNode->isLeaf()) {
+ for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Op = InstPatNode->getChild(i);
+ if (!Op->isLeaf()) {
+ PhysRegInputs->push_back("");
+ continue;
+ }
+
+ DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue());
+ Record *OpLeafRec = OpDI->getDef();
+ std::string PhysReg;
+ if (OpLeafRec->isSubClassOf("Register")) {
+ PhysReg += static_cast<StringInit*>(OpLeafRec->getValue( \
+ "Namespace")->getValue())->getValue();
+ PhysReg += "::";
+
+ std::vector<CodeGenRegister> Regs = Target.getRegisters();
+ for (unsigned i = 0; i < Regs.size(); ++i) {
+ if (Regs[i].TheDef == OpLeafRec) {
+ PhysReg += Regs[i].getName();
+ break;
+ }
+ }
+ }
+
+ PhysRegInputs->push_back(PhysReg);
+ }
+ } else
+ PhysRegInputs->push_back("");
+
+ // Get the predicate that guards this pattern.
+ std::string PredicateCheck = Pattern.getPredicateCheck();
+
+ // Ok, we found a pattern that we can handle. Remember it.
+ InstructionMemo Memo = {
+ Pattern.getDstPattern()->getOperator()->getName(),
+ DstRC,
+ SubRegNo,
+ PhysRegInputs
+ };
+ assert(!SimplePatterns[Operands][OpcodeName][VT][RetVT].count(PredicateCheck) &&
+ "Duplicate pattern!");
+ SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo;
+ }
+}
+
+void FastISelMap::PrintFunctionDefinitions(std::ostream &OS) {
+ // Now emit code for all the patterns that we collected.
+ for (OperandsOpcodeTypeRetPredMap::const_iterator OI = SimplePatterns.begin(),
+ OE = SimplePatterns.end(); OI != OE; ++OI) {
+ const OperandsSignature &Operands = OI->first;
+ const OpcodeTypeRetPredMap &OTM = OI->second;
+
+ for (OpcodeTypeRetPredMap::const_iterator I = OTM.begin(), E = OTM.end();
+ I != E; ++I) {
+ const std::string &Opcode = I->first;
+ const TypeRetPredMap &TM = I->second;
+
+ OS << "// FastEmit functions for " << Opcode << ".\n";
+ OS << "\n";
+
+ // Emit one function for each opcode,type pair.
+ for (TypeRetPredMap::const_iterator TI = TM.begin(), TE = TM.end();
+ TI != TE; ++TI) {
+ MVT::SimpleValueType VT = TI->first;
+ const RetPredMap &RM = TI->second;
+ if (RM.size() != 1) {
+ for (RetPredMap::const_iterator RI = RM.begin(), RE = RM.end();
+ RI != RE; ++RI) {
+ MVT::SimpleValueType RetVT = RI->first;
+ const PredMap &PM = RI->second;
+ bool HasPred = false;
+
+ OS << "unsigned FastEmit_"
+ << getLegalCName(Opcode)
+ << "_" << getLegalCName(getName(VT))
+ << "_" << getLegalCName(getName(RetVT)) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(";
+ Operands.PrintParameters(OS);
+ OS << ") {\n";
+
+ // Emit code for each possible instruction. There may be
+ // multiple if there are subtarget concerns.
+ for (PredMap::const_iterator PI = PM.begin(), PE = PM.end();
+ PI != PE; ++PI) {
+ std::string PredicateCheck = PI->first;
+ const InstructionMemo &Memo = PI->second;
+
+ if (PredicateCheck.empty()) {
+ assert(!HasPred &&
+ "Multiple instructions match, at least one has "
+ "a predicate and at least one doesn't!");
+ } else {
+ OS << " if (" + PredicateCheck + ") {\n";
+ OS << " ";
+ HasPred = true;
+ }
+
+ for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) {
+ if ((*Memo.PhysRegs)[i] != "")
+ OS << " TII.copyRegToReg(*MBB, MBB->end(), "
+ << (*Memo.PhysRegs)[i] << ", Op" << i << ", "
+ << "TM.getRegisterInfo()->getPhysicalRegisterRegClass("
+ << (*Memo.PhysRegs)[i] << "), "
+ << "MRI.getRegClass(Op" << i << "));\n";
+ }
+
+ OS << " return FastEmitInst_";
+ if (Memo.SubRegNo == (unsigned char)~0) {
+ Operands.PrintManglingSuffix(OS, *Memo.PhysRegs);
+ OS << "(" << InstNS << Memo.Name << ", ";
+ OS << InstNS << Memo.RC->getName() << "RegisterClass";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintArguments(OS, *Memo.PhysRegs);
+ OS << ");\n";
+ } else {
+ OS << "extractsubreg(" << getName(RetVT);
+ OS << ", Op0, ";
+ OS << (unsigned)Memo.SubRegNo;
+ OS << ");\n";
+ }
+
+ if (HasPred)
+ OS << " }\n";
+
+ }
+ // Return 0 if none of the predicates were satisfied.
+ if (HasPred)
+ OS << " return 0;\n";
+ OS << "}\n";
+ OS << "\n";
+ }
+
+ // Emit one function for the type that demultiplexes on return type.
+ OS << "unsigned FastEmit_"
+ << getLegalCName(Opcode) << "_"
+ << getLegalCName(getName(VT)) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(MVT::SimpleValueType RetVT";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintParameters(OS);
+ OS << ") {\nswitch (RetVT) {\n";
+ for (RetPredMap::const_iterator RI = RM.begin(), RE = RM.end();
+ RI != RE; ++RI) {
+ MVT::SimpleValueType RetVT = RI->first;
+ OS << " case " << getName(RetVT) << ": return FastEmit_"
+ << getLegalCName(Opcode) << "_" << getLegalCName(getName(VT))
+ << "_" << getLegalCName(getName(RetVT)) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(";
+ Operands.PrintArguments(OS);
+ OS << ");\n";
+ }
+ OS << " default: return 0;\n}\n}\n\n";
+
+ } else {
+ // Non-variadic return type.
+ OS << "unsigned FastEmit_"
+ << getLegalCName(Opcode) << "_"
+ << getLegalCName(getName(VT)) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(MVT::SimpleValueType RetVT";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintParameters(OS);
+ OS << ") {\n";
+
+ OS << " if (RetVT != " << getName(RM.begin()->first)
+ << ")\n return 0;\n";
+
+ const PredMap &PM = RM.begin()->second;
+ bool HasPred = false;
+
+ // Emit code for each possible instruction. There may be
+ // multiple if there are subtarget concerns.
+ for (PredMap::const_iterator PI = PM.begin(), PE = PM.end(); PI != PE;
+ ++PI) {
+ std::string PredicateCheck = PI->first;
+ const InstructionMemo &Memo = PI->second;
+
+ if (PredicateCheck.empty()) {
+ assert(!HasPred &&
+ "Multiple instructions match, at least one has "
+ "a predicate and at least one doesn't!");
+ } else {
+ OS << " if (" + PredicateCheck + ") {\n";
+ OS << " ";
+ HasPred = true;
+ }
+
+ for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) {
+ if ((*Memo.PhysRegs)[i] != "")
+ OS << " TII.copyRegToReg(*MBB, MBB->end(), "
+ << (*Memo.PhysRegs)[i] << ", Op" << i << ", "
+ << "TM.getRegisterInfo()->getPhysicalRegisterRegClass("
+ << (*Memo.PhysRegs)[i] << "), "
+ << "MRI.getRegClass(Op" << i << "));\n";
+ }
+
+ OS << " return FastEmitInst_";
+
+ if (Memo.SubRegNo == (unsigned char)~0) {
+ Operands.PrintManglingSuffix(OS, *Memo.PhysRegs);
+ OS << "(" << InstNS << Memo.Name << ", ";
+ OS << InstNS << Memo.RC->getName() << "RegisterClass";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintArguments(OS, *Memo.PhysRegs);
+ OS << ");\n";
+ } else {
+ OS << "extractsubreg(RetVT, Op0, ";
+ OS << (unsigned)Memo.SubRegNo;
+ OS << ");\n";
+ }
+
+ if (HasPred)
+ OS << " }\n";
+ }
+
+ // Return 0 if none of the predicates were satisfied.
+ if (HasPred)
+ OS << " return 0;\n";
+ OS << "}\n";
+ OS << "\n";
+ }
+ }
+
+ // Emit one function for the opcode that demultiplexes based on the type.
+ OS << "unsigned FastEmit_"
+ << getLegalCName(Opcode) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(MVT::SimpleValueType VT, MVT::SimpleValueType RetVT";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintParameters(OS);
+ OS << ") {\n";
+ OS << " switch (VT) {\n";
+ for (TypeRetPredMap::const_iterator TI = TM.begin(), TE = TM.end();
+ TI != TE; ++TI) {
+ MVT::SimpleValueType VT = TI->first;
+ std::string TypeName = getName(VT);
+ OS << " case " << TypeName << ": return FastEmit_"
+ << getLegalCName(Opcode) << "_" << getLegalCName(TypeName) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(RetVT";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintArguments(OS);
+ OS << ");\n";
+ }
+ OS << " default: return 0;\n";
+ OS << " }\n";
+ OS << "}\n";
+ OS << "\n";
+ }
+
+ OS << "// Top-level FastEmit function.\n";
+ OS << "\n";
+
+ // Emit one function for the operand signature that demultiplexes based
+ // on opcode and type.
+ OS << "unsigned FastEmit_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(MVT::SimpleValueType VT, MVT::SimpleValueType RetVT, ISD::NodeType Opcode";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintParameters(OS);
+ OS << ") {\n";
+ OS << " switch (Opcode) {\n";
+ for (OpcodeTypeRetPredMap::const_iterator I = OTM.begin(), E = OTM.end();
+ I != E; ++I) {
+ const std::string &Opcode = I->first;
+
+ OS << " case " << Opcode << ": return FastEmit_"
+ << getLegalCName(Opcode) << "_";
+ Operands.PrintManglingSuffix(OS);
+ OS << "(VT, RetVT";
+ if (!Operands.empty())
+ OS << ", ";
+ Operands.PrintArguments(OS);
+ OS << ");\n";
+ }
+ OS << " default: return 0;\n";
+ OS << " }\n";
+ OS << "}\n";
+ OS << "\n";
+ }
+}
+
+void FastISelEmitter::run(std::ostream &OS) {
+ const CodeGenTarget &Target = CGP.getTargetInfo();
+
+ // Determine the target's namespace name.
+ std::string InstNS = Target.getInstNamespace() + "::";
+ assert(InstNS.size() > 2 && "Can't determine target-specific namespace!");
+
+ EmitSourceFileHeader("\"Fast\" Instruction Selector for the " +
+ Target.getName() + " target", OS);
+
+ FastISelMap F(InstNS);
+ F.CollectPatterns(CGP);
+ F.PrintFunctionDefinitions(OS);
+}
+
+FastISelEmitter::FastISelEmitter(RecordKeeper &R)
+ : Records(R),
+ CGP(R) {
+}
+
diff --git a/utils/TableGen/FastISelEmitter.h b/utils/TableGen/FastISelEmitter.h
new file mode 100644
index 000000000000..4743ca9bfa01
--- /dev/null
+++ b/utils/TableGen/FastISelEmitter.h
@@ -0,0 +1,39 @@
+//===- FastISelEmitter.h - Generate an instruction selector -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits a "fast" instruction selector.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FASTISEL_EMITTER_H
+#define FASTISEL_EMITTER_H
+
+#include "TableGenBackend.h"
+#include "CodeGenDAGPatterns.h"
+
+namespace llvm {
+
+class CodeGenTarget;
+
+/// FastISelEmitter - The top-level class which coordinates construction
+/// and emission of the instruction selector.
+///
+class FastISelEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ CodeGenDAGPatterns CGP;
+public:
+ explicit FastISelEmitter(RecordKeeper &R);
+
+ // run - Output the isel, returning true on failure.
+ void run(std::ostream &OS);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp
new file mode 100644
index 000000000000..4b4791b61458
--- /dev/null
+++ b/utils/TableGen/InstrEnumEmitter.cpp
@@ -0,0 +1,55 @@
+//===- InstrEnumEmitter.cpp - Generate Instruction Set Enums --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting enums for each machine
+// instruction.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InstrEnumEmitter.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include <cstdio>
+using namespace llvm;
+
+// runEnums - Print out enum values for all of the instructions.
+void InstrEnumEmitter::run(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()) {
+ fprintf(stderr, "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";
+}
diff --git a/utils/TableGen/InstrEnumEmitter.h b/utils/TableGen/InstrEnumEmitter.h
new file mode 100644
index 000000000000..b39fef2d433c
--- /dev/null
+++ b/utils/TableGen/InstrEnumEmitter.h
@@ -0,0 +1,33 @@
+//===- InstrEnumEmitter.h - Generate Instruction Set Enums ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting enums for each machine
+// instruction.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INSTRENUM_EMITTER_H
+#define INSTRENUM_EMITTER_H
+
+#include "TableGenBackend.h"
+
+namespace llvm {
+
+class InstrEnumEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ InstrEnumEmitter(RecordKeeper &R) : Records(R) {}
+
+ // run - Output the instruction set description, returning true on failure.
+ void run(std::ostream &OS);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
new file mode 100644
index 000000000000..61dbe64af8f3
--- /dev/null
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -0,0 +1,381 @@
+//===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "Record.h"
+#include <algorithm>
+#include <iostream>
+using namespace llvm;
+
+static void PrintDefList(const std::vector<Record*> &Uses,
+ unsigned Num, std::ostream &OS) {
+ OS << "static const unsigned ImplicitList" << Num << "[] = { ";
+ for (unsigned i = 0, e = Uses.size(); i != e; ++i)
+ OS << getQualifiedName(Uses[i]) << ", ";
+ OS << "0 };\n";
+}
+
+static void PrintBarriers(std::vector<Record*> &Barriers,
+ unsigned Num, std::ostream &OS) {
+ OS << "static const TargetRegisterClass* Barriers" << Num << "[] = { ";
+ for (unsigned i = 0, e = Barriers.size(); i != e; ++i)
+ OS << "&" << getQualifiedName(Barriers[i]) << "RegClass, ";
+ OS << "NULL };\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Instruction Itinerary Information.
+//===----------------------------------------------------------------------===//
+
+struct RecordNameComparator {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getName() < Rec2->getName();
+ }
+};
+
+void InstrInfoEmitter::GatherItinClasses() {
+ std::vector<Record*> DefList =
+ Records.getAllDerivedDefinitions("InstrItinClass");
+ std::sort(DefList.begin(), DefList.end(), RecordNameComparator());
+
+ for (unsigned i = 0, N = DefList.size(); i < N; i++)
+ ItinClassMap[DefList[i]->getName()] = i;
+}
+
+unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) {
+ return ItinClassMap[InstRec->getValueAsDef("Itinerary")->getName()];
+}
+
+//===----------------------------------------------------------------------===//
+// Operand Info Emission.
+//===----------------------------------------------------------------------===//
+
+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 += "|(1<<TOI::LookupPtrRegClass)";
+
+ // Predicate operands. Check to see if the original unexpanded operand
+ // was of type PredicateOperand.
+ if (Inst.OperandList[i].Rec->isSubClassOf("PredicateOperand"))
+ Res += "|(1<<TOI::Predicate)";
+
+ // Optional def operands. Check to see if the original unexpanded operand
+ // was of type OptionalDefOperand.
+ if (Inst.OperandList[i].Rec->isSubClassOf("OptionalDefOperand"))
+ Res += "|(1<<TOI::OptionalDef)";
+
+ // Fill in constraint info.
+ Res += ", " + Inst.OperandList[i].Constraints[j];
+ Result.push_back(Res);
+ }
+ }
+
+ return Result;
+}
+
+void InstrInfoEmitter::EmitOperandInfo(std::ostream &OS,
+ OperandInfoMapTy &OperandInfoIDs) {
+ // ID #0 is for no operand info.
+ unsigned OperandListNum = 0;
+ OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum;
+
+ OS << "\n";
+ const CodeGenTarget &Target = CDP.getTargetInfo();
+ 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 = OperandInfoIDs[OperandInfo];
+ if (N != 0) continue;
+
+ N = ++OperandListNum;
+ OS << "static const TargetOperandInfo OperandInfo" << N << "[] = { ";
+ for (unsigned i = 0, e = OperandInfo.size(); i != e; ++i)
+ OS << "{ " << OperandInfo[i] << " }, ";
+ OS << "};\n";
+ }
+}
+
+void InstrInfoEmitter::DetectRegisterClassBarriers(std::vector<Record*> &Defs,
+ const std::vector<CodeGenRegisterClass> &RCs,
+ std::vector<Record*> &Barriers) {
+ std::set<Record*> DefSet;
+ unsigned NumDefs = Defs.size();
+ for (unsigned i = 0; i < NumDefs; ++i)
+ DefSet.insert(Defs[i]);
+
+ for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
+ const CodeGenRegisterClass &RC = RCs[i];
+ unsigned NumRegs = RC.Elements.size();
+ if (NumRegs > NumDefs)
+ continue; // Can't possibly clobber this RC.
+
+ bool Clobber = true;
+ for (unsigned j = 0; j < NumRegs; ++j) {
+ Record *Reg = RC.Elements[j];
+ if (!DefSet.count(Reg)) {
+ Clobber = false;
+ break;
+ }
+ }
+ if (Clobber)
+ Barriers.push_back(RC.TheDef);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Main Output.
+//===----------------------------------------------------------------------===//
+
+// 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 = CDP.getTargetInfo();
+ const std::string &TargetName = Target.getName();
+ Record *InstrInfo = Target.getInstructionSet();
+ const std::vector<CodeGenRegisterClass> &RCs = Target.getRegisterClasses();
+
+ // Keep track of all of the def lists we have emitted already.
+ std::map<std::vector<Record*>, unsigned> EmittedLists;
+ unsigned ListNumber = 0;
+ std::map<std::vector<Record*>, unsigned> EmittedBarriers;
+ unsigned BarrierNumber = 0;
+ std::map<Record*, unsigned> BarriersMap;
+
+ // 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()) {
+ std::vector<Record*> RCBarriers;
+ DetectRegisterClassBarriers(Defs, RCs, RCBarriers);
+ if (!RCBarriers.empty()) {
+ unsigned &IB = EmittedBarriers[RCBarriers];
+ if (!IB) PrintBarriers(RCBarriers, IB = ++BarrierNumber, OS);
+ BarriersMap.insert(std::make_pair(Inst, IB));
+ }
+
+ unsigned &IL = EmittedLists[Defs];
+ if (!IL) PrintDefList(Defs, IL = ++ListNumber, OS);
+ }
+ }
+
+ OperandInfoMapTy OperandInfoIDs;
+
+ // Emit all of the operand info records.
+ EmitOperandInfo(OS, OperandInfoIDs);
+
+ // Emit all of the TargetInstrDesc records in their ENUM ordering.
+ //
+ OS << "\nstatic const TargetInstrDesc " << 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,
+ BarriersMap, OperandInfoIDs, 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<Record*, unsigned> &BarriersMap,
+ const OperandInfoMapTy &OpInfo,
+ std::ostream &OS) {
+ int MinOperands = 0;
+ if (!Inst.OperandList.empty())
+ // Each logical operand can be multiple MI operands.
+ MinOperands = Inst.OperandList.back().MIOperandNo +
+ Inst.OperandList.back().MINumOperands;
+
+ OS << " { ";
+ OS << Num << ",\t" << MinOperands << ",\t"
+ << Inst.NumDefs << ",\t" << getItinClassNumber(Inst.TheDef)
+ << ",\t\"" << Inst.TheDef->getName() << "\", 0";
+
+ // Emit all of the target indepedent flags...
+ if (Inst.isReturn) OS << "|(1<<TID::Return)";
+ if (Inst.isBranch) OS << "|(1<<TID::Branch)";
+ if (Inst.isIndirectBranch) OS << "|(1<<TID::IndirectBranch)";
+ if (Inst.isBarrier) OS << "|(1<<TID::Barrier)";
+ if (Inst.hasDelaySlot) OS << "|(1<<TID::DelaySlot)";
+ if (Inst.isCall) OS << "|(1<<TID::Call)";
+ if (Inst.canFoldAsLoad) OS << "|(1<<TID::FoldableAsLoad)";
+ if (Inst.mayLoad) OS << "|(1<<TID::MayLoad)";
+ if (Inst.mayStore) OS << "|(1<<TID::MayStore)";
+ if (Inst.isPredicable) OS << "|(1<<TID::Predicable)";
+ if (Inst.isConvertibleToThreeAddress) OS << "|(1<<TID::ConvertibleTo3Addr)";
+ if (Inst.isCommutable) OS << "|(1<<TID::Commutable)";
+ if (Inst.isTerminator) OS << "|(1<<TID::Terminator)";
+ if (Inst.isReMaterializable) OS << "|(1<<TID::Rematerializable)";
+ if (Inst.isNotDuplicable) OS << "|(1<<TID::NotDuplicable)";
+ if (Inst.hasOptionalDef) OS << "|(1<<TID::HasOptionalDef)";
+ if (Inst.usesCustomDAGSchedInserter)
+ OS << "|(1<<TID::UsesCustomDAGSchedInserter)";
+ if (Inst.isVariadic) OS << "|(1<<TID::Variadic)";
+ if (Inst.hasSideEffects) OS << "|(1<<TID::UnmodeledSideEffects)";
+ if (Inst.isAsCheapAsAMove) OS << "|(1<<TID::CheapAsAMove)";
+ 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] << ", ";
+
+ std::map<Record*, unsigned>::iterator BI = BarriersMap.find(Inst.TheDef);
+ if (BI == BarriersMap.end())
+ OS << "NULL, ";
+ else
+ OS << "Barriers" << BI->second << ", ";
+
+ // Emit the operand info.
+ std::vector<std::string> OperandInfo = GetOperandInfo(Inst);
+ if (OperandInfo.empty())
+ OS << "0";
+ else
+ OS << "OperandInfo" << OpInfo.find(OperandInfo)->second;
+
+ OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
+}
+
+
+void InstrInfoEmitter::emitShiftedValue(Record *R, StringInit *Val,
+ IntInit *ShiftInt, std::ostream &OS) {
+ if (Val == 0 || ShiftInt == 0)
+ throw std::string("Illegal value or shift amount in TargetInfo*!");
+ RecordVal *RV = R->getValue(Val->getValue());
+ int Shift = ShiftInt->getValue();
+
+ if (RV == 0 || RV->getValue() == 0) {
+ // This isn't an error if this is a builtin instruction.
+ if (R->getName() != "PHI" &&
+ R->getName() != "INLINEASM" &&
+ R->getName() != "DBG_LABEL" &&
+ R->getName() != "EH_LABEL" &&
+ R->getName() != "GC_LABEL" &&
+ R->getName() != "DECLARE" &&
+ R->getName() != "EXTRACT_SUBREG" &&
+ R->getName() != "INSERT_SUBREG" &&
+ R->getName() != "IMPLICIT_DEF" &&
+ R->getName() != "SUBREG_TO_REG" &&
+ R->getName() != "COPY_TO_REGCLASS")
+ 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;
+ }
+
+ std::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 000000000000..870ea0c58780
--- /dev/null
+++ b/utils/TableGen/InstrInfoEmitter.h
@@ -0,0 +1,68 @@
+//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "CodeGenDAGPatterns.h"
+#include <vector>
+#include <map>
+
+namespace llvm {
+
+class StringInit;
+class IntInit;
+class ListInit;
+class CodeGenInstruction;
+
+class InstrInfoEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ CodeGenDAGPatterns CDP;
+ std::map<std::string, unsigned> ItinClassMap;
+
+public:
+ InstrInfoEmitter(RecordKeeper &R) : Records(R), CDP(R) { }
+
+ // run - Output the instruction set description, returning true on failure.
+ void run(std::ostream &OS);
+
+private:
+ typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
+
+ void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
+ Record *InstrInfo,
+ std::map<std::vector<Record*>, unsigned> &EL,
+ std::map<Record*, unsigned> &BM,
+ const OperandInfoMapTy &OpInfo,
+ std::ostream &OS);
+ void emitShiftedValue(Record *R, StringInit *Val, IntInit *Shift,
+ std::ostream &OS);
+
+ // Itinerary information.
+ void GatherItinClasses();
+ unsigned getItinClassNumber(const Record *InstRec);
+
+ // Operand information.
+ void EmitOperandInfo(std::ostream &OS, OperandInfoMapTy &OperandInfoIDs);
+ std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
+
+ void DetectRegisterClassBarriers(std::vector<Record*> &Defs,
+ const std::vector<CodeGenRegisterClass> &RCs,
+ std::vector<Record*> &Barriers);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
new file mode 100644
index 000000000000..2d28fb72e343
--- /dev/null
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -0,0 +1,716 @@
+//===- IntrinsicEmitter.cpp - Generate intrinsic information --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits information about intrinsic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenTarget.h"
+#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, TargetOnly);
+
+ if (TargetOnly && !Ints.empty())
+ TargetPrefix = Ints[0].TargetPrefix;
+
+ // Emit the enum information.
+ EmitEnumInfo(Ints, OS);
+
+ // Emit the intrinsic ID -> name table.
+ EmitIntrinsicToNameTable(Ints, OS);
+
+ // Emit the intrinsic ID -> overload table.
+ EmitIntrinsicToOverloadTable(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 the intrinsic parameter attributes.
+ EmitAttributes(Ints, OS);
+
+ // Emit intrinsic alias analysis mod/ref behavior.
+ EmitModRefBehavior(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() + 1) << ")) return " << TargetPrefix << "Intrinsic::"
+ << Ints[I->second].EnumName << ";\n";
+ else
+ OS << " if (Len == " << I->first.size()
+ << " && !memcmp(Name, \"" << I->first << "\", "
+ << I->first.size() << ")) return " << TargetPrefix << "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";
+}
+
+void IntrinsicEmitter::
+EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// Intrinsic ID to overload table\n";
+ OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n";
+ OS << " // Note that entry #0 is the invalid intrinsic!\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ OS << " ";
+ if (Ints[i].isOverloaded)
+ OS << "true";
+ else
+ OS << "false";
+ OS << ",\n";
+ }
+ OS << "#endif\n\n";
+}
+
+static void EmitTypeForValueType(std::ostream &OS, MVT::SimpleValueType VT) {
+ if (MVT(VT).isInteger()) {
+ unsigned BitWidth = MVT(VT).getSizeInBits();
+ OS << "IntegerType::get(" << BitWidth << ")";
+ } else if (VT == MVT::Other) {
+ // MVT::OtherVT is used to mean the empty struct type here.
+ OS << "StructType::get(std::vector<const Type *>())";
+ } else if (VT == MVT::f32) {
+ OS << "Type::FloatTy";
+ } else if (VT == MVT::f64) {
+ OS << "Type::DoubleTy";
+ } else if (VT == MVT::f80) {
+ OS << "Type::X86_FP80Ty";
+ } else if (VT == MVT::f128) {
+ OS << "Type::FP128Ty";
+ } else if (VT == MVT::ppcf128) {
+ OS << "Type::PPC_FP128Ty";
+ } else if (VT == MVT::isVoid) {
+ OS << "Type::VoidTy";
+ } else {
+ assert(false && "Unsupported ValueType!");
+ }
+}
+
+static void EmitTypeGenerate(std::ostream &OS, const Record *ArgType,
+ unsigned &ArgNo);
+
+static void EmitTypeGenerate(std::ostream &OS,
+ const std::vector<Record*> &ArgTypes,
+ unsigned &ArgNo) {
+ if (ArgTypes.size() == 1) {
+ EmitTypeGenerate(OS, ArgTypes.front(), ArgNo);
+ return;
+ }
+
+ OS << "StructType::get(";
+
+ for (std::vector<Record*>::const_iterator
+ I = ArgTypes.begin(), E = ArgTypes.end(); I != E; ++I) {
+ EmitTypeGenerate(OS, *I, ArgNo);
+ OS << ", ";
+ }
+
+ OS << " NULL)";
+}
+
+static void EmitTypeGenerate(std::ostream &OS, const Record *ArgType,
+ unsigned &ArgNo) {
+ MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
+
+ if (ArgType->isSubClassOf("LLVMMatchType")) {
+ unsigned Number = ArgType->getValueAsInt("Number");
+ assert(Number < ArgNo && "Invalid matching number!");
+ if (ArgType->isSubClassOf("LLVMExtendedElementVectorType"))
+ OS << "VectorType::getExtendedElementVectorType"
+ << "(dyn_cast<VectorType>(Tys[" << Number << "]))";
+ else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType"))
+ OS << "VectorType::getTruncatedElementVectorType"
+ << "(dyn_cast<VectorType>(Tys[" << Number << "]))";
+ else
+ OS << "Tys[" << Number << "]";
+ } else if (VT == MVT::iAny || VT == MVT::fAny) {
+ // 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 overloaded type. Getting this wrong
+ // leads to very subtle bugs!
+ OS << "Tys[" << ArgNo++ << "]";
+ } else if (MVT(VT).isVector()) {
+ MVT VVT = VT;
+ OS << "VectorType::get(";
+ EmitTypeForValueType(OS, VVT.getVectorElementType().getSimpleVT());
+ OS << ", " << VVT.getVectorNumElements() << ")";
+ } else if (VT == MVT::iPTR) {
+ OS << "PointerType::getUnqual(";
+ EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo);
+ OS << ")";
+ } else if (VT == MVT::iPTRAny) {
+ // Make sure the user has passed us an argument type to overload. If not,
+ // treat it as an ordinary (not overloaded) intrinsic.
+ OS << "(" << ArgNo << " < numTys) ? Tys[" << ArgNo
+ << "] : PointerType::getUnqual(";
+ EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo);
+ OS << ")";
+ ++ArgNo;
+ } else if (VT == MVT::isVoid) {
+ if (ArgNo == 0)
+ OS << "Type::VoidTy";
+ else
+ // MVT::isVoid is used to mean varargs here.
+ OS << "...";
+ } else {
+ EmitTypeForValueType(OS, VT);
+ }
+}
+
+/// RecordListComparator - Provide a deterministic comparator for lists of
+/// records.
+namespace {
+ typedef std::pair<std::vector<Record*>, std::vector<Record*> > RecPair;
+ struct RecordListComparator {
+ bool operator()(const RecPair &LHS,
+ const RecPair &RHS) const {
+ unsigned i = 0;
+ const std::vector<Record*> *LHSVec = &LHS.first;
+ const std::vector<Record*> *RHSVec = &RHS.first;
+ unsigned RHSSize = RHSVec->size();
+ unsigned LHSSize = LHSVec->size();
+
+ do {
+ if (i == RHSSize) return false; // RHS is shorter than LHS.
+ if ((*LHSVec)[i] != (*RHSVec)[i])
+ return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
+ } while (++i != LHSSize);
+
+ if (i != RHSSize) return true;
+
+ i = 0;
+ LHSVec = &LHS.second;
+ RHSVec = &RHS.second;
+ RHSSize = RHSVec->size();
+ LHSSize = LHSVec->size();
+
+ for (i = 0; i != LHSSize; ++i) {
+ if (i == RHSSize) return false; // RHS is shorter than LHS.
+ if ((*LHSVec)[i] != (*RHSVec)[i])
+ return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
+ }
+
+ return i != RHSSize;
+ }
+ };
+}
+
+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<RecPair, std::vector<unsigned>, RecordListComparator> MapTy;
+ MapTy UniqueArgInfos;
+
+ // Compute the unique argument type info.
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs,
+ Ints[i].IS.ParamTypeDefs)].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 RecPair &ArgTypes = I->first;
+ const std::vector<Record*> &RetTys = ArgTypes.first;
+ const std::vector<Record*> &ParamTys = ArgTypes.second;
+
+ OS << " VerifyIntrinsicPrototype(ID, IF, " << RetTys.size() << ", "
+ << ParamTys.size();
+
+ // Emit return types.
+ for (unsigned j = 0, je = RetTys.size(); j != je; ++j) {
+ Record *ArgType = RetTys[j];
+ OS << ", ";
+
+ if (ArgType->isSubClassOf("LLVMMatchType")) {
+ unsigned Number = ArgType->getValueAsInt("Number");
+ if (ArgType->isSubClassOf("LLVMExtendedElementVectorType"))
+ OS << "~(ExtendedElementVectorType | " << Number << ")";
+ else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType"))
+ OS << "~(TruncatedElementVectorType | " << Number << ")";
+ else
+ OS << "~" << Number;
+ } else {
+ MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
+ OS << getEnumName(VT);
+
+ if (VT == MVT::isVoid && j != 0 && j != je - 1)
+ throw "Var arg type not last argument";
+ }
+ }
+
+ // Emit the parameter types.
+ for (unsigned j = 0, je = ParamTys.size(); j != je; ++j) {
+ Record *ArgType = ParamTys[j];
+ OS << ", ";
+
+ if (ArgType->isSubClassOf("LLVMMatchType")) {
+ unsigned Number = ArgType->getValueAsInt("Number");
+ if (ArgType->isSubClassOf("LLVMExtendedElementVectorType"))
+ OS << "~(ExtendedElementVectorType | " << Number << ")";
+ else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType"))
+ OS << "~(TruncatedElementVectorType | " << Number << ")";
+ else
+ OS << "~" << Number;
+ } else {
+ MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
+ OS << getEnumName(VT);
+
+ if (VT == MVT::isVoid && j != 0 && j != je - 1)
+ throw "Var arg type not last argument";
+ }
+ }
+
+ OS << ");\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<RecPair, std::vector<unsigned>, RecordListComparator> MapTy;
+ MapTy UniqueArgInfos;
+
+ // Compute the unique argument type info.
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs,
+ Ints[i].IS.ParamTypeDefs)].push_back(i);
+
+ // Loop through the array, emitting one generator for each batch.
+ std::string IntrinsicStr = TargetPrefix + "Intrinsic::";
+
+ 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 " << IntrinsicStr << Ints[I->second[i]].EnumName
+ << ":\t\t// " << Ints[I->second[i]].Name << "\n";
+
+ const RecPair &ArgTypes = I->first;
+ const std::vector<Record*> &RetTys = ArgTypes.first;
+ const std::vector<Record*> &ParamTys = ArgTypes.second;
+
+ unsigned N = ParamTys.size();
+
+ if (N > 1 &&
+ getValueType(ParamTys[N - 1]->getValueAsDef("VT")) == MVT::isVoid) {
+ OS << " IsVarArg = true;\n";
+ --N;
+ }
+
+ unsigned ArgNo = 0;
+ OS << " ResultTy = ";
+ EmitTypeGenerate(OS, RetTys, ArgNo);
+ OS << ";\n";
+
+ for (unsigned j = 0; j != N; ++j) {
+ OS << " ArgTys.push_back(";
+ EmitTypeGenerate(OS, ParamTys[j], ArgNo);
+ OS << ");\n";
+ }
+
+ OS << " break;\n";
+ }
+
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+/// EmitAttributes - This emits the Intrinsic::getAttributes method.
+void IntrinsicEmitter::
+EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS) {
+ OS << "// Add parameter attributes that are not common to all intrinsics.\n";
+ OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n";
+ if (TargetOnly)
+ OS << "static AttrListPtr getAttributes(" << TargetPrefix
+ << "Intrinsic::ID id) {";
+ else
+ OS << "AttrListPtr Intrinsic::getAttributes(ID id) {";
+ OS << " // No intrinsic can throw exceptions.\n";
+ OS << " Attributes Attr = Attribute::NoUnwind;\n";
+ OS << " switch (id) {\n";
+ OS << " default: break;\n";
+ unsigned MaxArgAttrs = 0;
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ MaxArgAttrs =
+ std::max(MaxArgAttrs, unsigned(Ints[i].ArgumentAttributes.size()));
+ switch (Ints[i].ModRef) {
+ default: break;
+ case CodeGenIntrinsic::NoMem:
+ OS << " case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName
+ << ":\n";
+ break;
+ }
+ }
+ OS << " Attr |= Attribute::ReadNone; // These do not access memory.\n";
+ OS << " break;\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ switch (Ints[i].ModRef) {
+ default: break;
+ case CodeGenIntrinsic::ReadArgMem:
+ case CodeGenIntrinsic::ReadMem:
+ OS << " case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName
+ << ":\n";
+ break;
+ }
+ }
+ OS << " Attr |= Attribute::ReadOnly; // These do not write memory.\n";
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " AttributeWithIndex AWI[" << MaxArgAttrs+1 << "];\n";
+ OS << " unsigned NumAttrs = 0;\n";
+ OS << " switch (id) {\n";
+ OS << " default: break;\n";
+
+ // Add argument attributes for any intrinsics that have them.
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ if (Ints[i].ArgumentAttributes.empty()) continue;
+
+ OS << " case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName
+ << ":\n";
+
+ std::vector<std::pair<unsigned, CodeGenIntrinsic::ArgAttribute> > ArgAttrs =
+ Ints[i].ArgumentAttributes;
+ // Sort by argument index.
+ std::sort(ArgAttrs.begin(), ArgAttrs.end());
+
+ unsigned NumArgsWithAttrs = 0;
+
+ while (!ArgAttrs.empty()) {
+ unsigned ArgNo = ArgAttrs[0].first;
+
+ OS << " AWI[" << NumArgsWithAttrs++ << "] = AttributeWithIndex::get("
+ << ArgNo+1 << ", 0";
+
+ while (!ArgAttrs.empty() && ArgAttrs[0].first == ArgNo) {
+ switch (ArgAttrs[0].second) {
+ default: assert(0 && "Unknown arg attribute");
+ case CodeGenIntrinsic::NoCapture:
+ OS << "|Attribute::NoCapture";
+ break;
+ }
+ ArgAttrs.erase(ArgAttrs.begin());
+ }
+ OS << ");\n";
+ }
+
+ OS << " NumAttrs = " << NumArgsWithAttrs << ";\n";
+ OS << " break;\n";
+ }
+
+ OS << " }\n";
+ OS << " AWI[NumAttrs] = AttributeWithIndex::get(~0, Attr);\n";
+ OS << " return AttrListPtr::get(AWI, NumAttrs+1);\n";
+ OS << "}\n";
+ OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n";
+}
+
+/// EmitModRefBehavior - Determine intrinsic alias analysis mod/ref behavior.
+void IntrinsicEmitter::
+EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS){
+ OS << "// Determine intrinsic alias analysis mod/ref behavior.\n";
+ OS << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n";
+ OS << "switch (id) {\n";
+ OS << "default:\n return UnknownModRefBehavior;\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ if (Ints[i].ModRef == CodeGenIntrinsic::WriteMem)
+ continue;
+ OS << "case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName
+ << ":\n";
+ switch (Ints[i].ModRef) {
+ default:
+ assert(false && "Unknown Mod/Ref type!");
+ case CodeGenIntrinsic::NoMem:
+ OS << " return DoesNotAccessMemory;\n";
+ break;
+ case CodeGenIntrinsic::ReadArgMem:
+ case CodeGenIntrinsic::ReadMem:
+ OS << " return OnlyReadsMemory;\n";
+ break;
+ case CodeGenIntrinsic::WriteArgMem:
+ OS << " return AccessesArguments;\n";
+ break;
+ }
+ }
+ OS << "}\n";
+ OS << "#endif // GET_INTRINSIC_MODREF_BEHAVIOR\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";
+}
+
+/// EmitBuiltinComparisons - Emit comparisons to determine whether the specified
+/// sorted range of builtin names is equal to the current builtin. This breaks
+/// it down into a simple tree.
+///
+/// At this point, we know that all the builtins in the range have the same name
+/// for the first 'CharStart' characters. Only the end of the name needs to be
+/// discriminated.
+typedef std::map<std::string, std::string>::const_iterator StrMapIterator;
+static void EmitBuiltinComparisons(StrMapIterator Start, StrMapIterator End,
+ unsigned CharStart, unsigned Indent,
+ std::string TargetPrefix, std::ostream &OS) {
+ if (Start == End) return; // empty range.
+
+ // Determine what, if anything, is the same about all these strings.
+ std::string CommonString = Start->first;
+ unsigned NumInRange = 0;
+ for (StrMapIterator I = Start; I != End; ++I, ++NumInRange) {
+ // Find the first character that doesn't match.
+ const std::string &ThisStr = I->first;
+ unsigned NonMatchChar = CharStart;
+ while (NonMatchChar < CommonString.size() &&
+ NonMatchChar < ThisStr.size() &&
+ CommonString[NonMatchChar] == ThisStr[NonMatchChar])
+ ++NonMatchChar;
+ // Truncate off pieces that don't match.
+ CommonString.resize(NonMatchChar);
+ }
+
+ // Just compare the rest of the string.
+ if (NumInRange == 1) {
+ if (CharStart != CommonString.size()) {
+ OS << std::string(Indent*2, ' ') << "if (!memcmp(BuiltinName";
+ if (CharStart) OS << "+" << CharStart;
+ OS << ", \"" << (CommonString.c_str()+CharStart) << "\", ";
+ OS << CommonString.size() - CharStart << "))\n";
+ ++Indent;
+ }
+ OS << std::string(Indent*2, ' ') << "IntrinsicID = " << TargetPrefix
+ << "Intrinsic::";
+ OS << Start->second << ";\n";
+ return;
+ }
+
+ // At this point, we potentially have a common prefix for these builtins, emit
+ // a check for this common prefix.
+ if (CommonString.size() != CharStart) {
+ OS << std::string(Indent*2, ' ') << "if (!memcmp(BuiltinName";
+ if (CharStart) OS << "+" << CharStart;
+ OS << ", \"" << (CommonString.c_str()+CharStart) << "\", ";
+ OS << CommonString.size()-CharStart << ")) {\n";
+
+ EmitBuiltinComparisons(Start, End, CommonString.size(), Indent+1,
+ TargetPrefix, OS);
+ OS << std::string(Indent*2, ' ') << "}\n";
+ return;
+ }
+
+ // Output a switch on the character that differs across the set.
+ OS << std::string(Indent*2, ' ') << "switch (BuiltinName[" << CharStart
+ << "]) {";
+ if (CharStart)
+ OS << " // \"" << std::string(Start->first.begin(),
+ Start->first.begin()+CharStart) << "\"";
+ OS << "\n";
+
+ for (StrMapIterator I = Start; I != End; ) {
+ char ThisChar = I->first[CharStart];
+ OS << std::string(Indent*2, ' ') << "case '" << ThisChar << "':\n";
+ // Figure out the range that has this common character.
+ StrMapIterator NextChar = I;
+ for (++NextChar; NextChar != End && NextChar->first[CharStart] == ThisChar;
+ ++NextChar)
+ /*empty*/;
+ EmitBuiltinComparisons(I, NextChar, CharStart+1, Indent+1, TargetPrefix,OS);
+ OS << std::string(Indent*2, ' ') << " break;\n";
+ I = NextChar;
+ }
+ OS << std::string(Indent*2, ' ') << "}\n";
+}
+
+/// EmitTargetBuiltins - All of the builtins in the specified map are for the
+/// same target, and we already checked it.
+static void EmitTargetBuiltins(const std::map<std::string, std::string> &BIM,
+ const std::string &TargetPrefix,
+ std::ostream &OS) {
+ // Rearrange the builtins by length.
+ std::vector<std::map<std::string, std::string> > BuiltinsByLen;
+ BuiltinsByLen.reserve(100);
+
+ for (StrMapIterator I = BIM.begin(), E = BIM.end(); I != E; ++I) {
+ if (I->first.size() >= BuiltinsByLen.size())
+ BuiltinsByLen.resize(I->first.size()+1);
+ BuiltinsByLen[I->first.size()].insert(*I);
+ }
+
+ // Now that we have all the builtins by their length, emit a switch stmt.
+ OS << " switch (strlen(BuiltinName)) {\n";
+ OS << " default: break;\n";
+ for (unsigned i = 0, e = BuiltinsByLen.size(); i != e; ++i) {
+ if (BuiltinsByLen[i].empty()) continue;
+ OS << " case " << i << ":\n";
+ EmitBuiltinComparisons(BuiltinsByLen[i].begin(), BuiltinsByLen[i].end(),
+ 0, 3, TargetPrefix, OS);
+ OS << " break;\n";
+ }
+ OS << " }\n";
+}
+
+
+void IntrinsicEmitter::
+EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ typedef std::map<std::string, std::map<std::string, std::string> > BIMTy;
+ BIMTy BuiltinMap;
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ if (!Ints[i].GCCBuiltinName.empty()) {
+ // Get the map for this target prefix.
+ std::map<std::string, std::string> &BIM =BuiltinMap[Ints[i].TargetPrefix];
+
+ if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName,
+ 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";
+
+ if (TargetOnly) {
+ OS << "static " << TargetPrefix << "Intrinsic::ID "
+ << "getIntrinsicForGCCBuiltin(const char "
+ << "*TargetPrefix, const char *BuiltinName) {\n";
+ OS << " " << TargetPrefix << "Intrinsic::ID IntrinsicID = ";
+ } else {
+ OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char "
+ << "*TargetPrefix, const char *BuiltinName) {\n";
+ OS << " Intrinsic::ID IntrinsicID = ";
+ }
+
+ if (TargetOnly)
+ OS << "(" << TargetPrefix<< "Intrinsic::ID)";
+
+ OS << "Intrinsic::not_intrinsic;\n";
+
+ // Note: this could emit significantly better code if we cared.
+ for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){
+ OS << " ";
+ if (!I->first.empty())
+ OS << "if (!strcmp(TargetPrefix, \"" << I->first << "\")) ";
+ else
+ OS << "/* Target Independent Builtins */ ";
+ OS << "{\n";
+
+ // Emit the comparisons for this target prefix.
+ EmitTargetBuiltins(I->second, TargetPrefix, OS);
+ OS << " }\n";
+ }
+ OS << " return IntrinsicID;\n";
+ OS << "}\n";
+ OS << "#endif\n\n";
+}
diff --git a/utils/TableGen/IntrinsicEmitter.h b/utils/TableGen/IntrinsicEmitter.h
new file mode 100644
index 000000000000..1619d0224292
--- /dev/null
+++ b/utils/TableGen/IntrinsicEmitter.h
@@ -0,0 +1,60 @@
+//===- IntrinsicEmitter.h - Generate intrinsic information ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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;
+ bool TargetOnly;
+ std::string TargetPrefix;
+
+ public:
+ IntrinsicEmitter(RecordKeeper &R, bool T = false)
+ : Records(R), TargetOnly(T) {}
+
+ 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 EmitIntrinsicToOverloadTable(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 EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitModRefBehavior(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/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
new file mode 100644
index 000000000000..d7e85507141e
--- /dev/null
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -0,0 +1,2131 @@
+//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open
+// Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting LLVMC configuration code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLVMCConfigurationEmitter.h"
+#include "Record.h"
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Streams.h"
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <stdexcept>
+#include <string>
+#include <typeinfo>
+
+using namespace llvm;
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+/// Typedefs
+
+typedef std::vector<Record*> RecordVector;
+typedef std::vector<std::string> StrVector;
+
+//===----------------------------------------------------------------------===//
+/// Constants
+
+// Indentation strings.
+const char * Indent1 = " ";
+const char * Indent2 = " ";
+const char * Indent3 = " ";
+
+// Default help string.
+const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED";
+
+// Name for the "sink" option.
+const char * SinkOptionName = "AutoGeneratedSinkOption";
+
+//===----------------------------------------------------------------------===//
+/// Helper functions
+
+/// Id - An 'identity' function object.
+struct Id {
+ template<typename T>
+ void operator()(const T&) const {
+ }
+};
+
+int InitPtrToInt(const Init* ptr) {
+ const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
+ return val.getValue();
+}
+
+const std::string& InitPtrToString(const Init* ptr) {
+ const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
+ return val.getValue();
+}
+
+const ListInit& InitPtrToList(const Init* ptr) {
+ const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
+ return val;
+}
+
+const DagInit& InitPtrToDag(const Init* ptr) {
+ const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
+ return val;
+}
+
+// checkNumberOfArguments - Ensure that the number of args in d is
+// less than or equal to min_arguments, otherwise throw an exception.
+void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
+ if (!d || d->getNumArgs() < min_arguments)
+ throw d->getOperator()->getAsString()
+ + ": too few arguments!";
+}
+
+// isDagEmpty - is this DAG marked with an empty marker?
+bool isDagEmpty (const DagInit* d) {
+ return d->getOperator()->getAsString() == "empty";
+}
+
+// EscapeVariableName - Escape commas and other symbols not allowed
+// in the C++ variable names. Makes it possible to use options named
+// like "Wa," (useful for prefix options).
+std::string EscapeVariableName(const std::string& Var) {
+ std::string ret;
+ for (unsigned i = 0; i != Var.size(); ++i) {
+ char cur_char = Var[i];
+ if (cur_char == ',') {
+ ret += "_comma_";
+ }
+ else if (cur_char == '+') {
+ ret += "_plus_";
+ }
+ else if (cur_char == '-') {
+ ret += "_dash_";
+ }
+ else {
+ ret.push_back(cur_char);
+ }
+ }
+ return ret;
+}
+
+/// oneOf - Does the input string contain this character?
+bool oneOf(const char* lst, char c) {
+ while (*lst) {
+ if (*lst++ == c)
+ return true;
+ }
+ return false;
+}
+
+template <class I, class S>
+void checkedIncrement(I& P, I E, S ErrorString) {
+ ++P;
+ if (P == E)
+ throw ErrorString;
+}
+
+//===----------------------------------------------------------------------===//
+/// Back-end specific code
+
+
+/// OptionType - One of six different option types. See the
+/// documentation for detailed description of differences.
+namespace OptionType {
+ enum OptionType { Alias, Switch, Parameter, ParameterList,
+ Prefix, PrefixList};
+
+bool IsList (OptionType t) {
+ return (t == ParameterList || t == PrefixList);
+}
+
+bool IsSwitch (OptionType t) {
+ return (t == Switch);
+}
+
+bool IsParameter (OptionType t) {
+ return (t == Parameter || t == Prefix);
+}
+
+}
+
+OptionType::OptionType stringToOptionType(const std::string& T) {
+ if (T == "alias_option")
+ return OptionType::Alias;
+ else if (T == "switch_option")
+ return OptionType::Switch;
+ else if (T == "parameter_option")
+ return OptionType::Parameter;
+ else if (T == "parameter_list_option")
+ return OptionType::ParameterList;
+ else if (T == "prefix_option")
+ return OptionType::Prefix;
+ else if (T == "prefix_list_option")
+ return OptionType::PrefixList;
+ else
+ throw "Unknown option type: " + T + '!';
+}
+
+namespace OptionDescriptionFlags {
+ enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
+ ReallyHidden = 0x4, Extern = 0x8,
+ OneOrMore = 0x10, ZeroOrOne = 0x20 };
+}
+
+/// OptionDescription - Represents data contained in a single
+/// OptionList entry.
+struct OptionDescription {
+ OptionType::OptionType Type;
+ std::string Name;
+ unsigned Flags;
+ std::string Help;
+ unsigned MultiVal;
+
+ OptionDescription(OptionType::OptionType t = OptionType::Switch,
+ const std::string& n = "",
+ const std::string& h = DefaultHelpString)
+ : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1)
+ {}
+
+ /// GenTypeDeclaration - Returns the C++ variable type of this
+ /// option.
+ const char* GenTypeDeclaration() const;
+
+ /// GenVariableName - Returns the variable name used in the
+ /// generated C++ code.
+ std::string GenVariableName() const;
+
+ /// Merge - Merge two option descriptions.
+ void Merge (const OptionDescription& other);
+
+ // Misc convenient getters/setters.
+
+ bool isAlias() const;
+
+ bool isMultiVal() const;
+
+ bool isExtern() const;
+ void setExtern();
+
+ bool isRequired() const;
+ void setRequired();
+
+ bool isOneOrMore() const;
+ void setOneOrMore();
+
+ bool isZeroOrOne() const;
+ void setZeroOrOne();
+
+ bool isHidden() const;
+ void setHidden();
+
+ bool isReallyHidden() const;
+ void setReallyHidden();
+
+};
+
+void OptionDescription::Merge (const OptionDescription& other)
+{
+ if (other.Type != Type)
+ throw "Conflicting definitions for the option " + Name + "!";
+
+ if (Help == other.Help || Help == DefaultHelpString)
+ Help = other.Help;
+ else if (other.Help != DefaultHelpString) {
+ llvm::cerr << "Warning: several different help strings"
+ " defined for option " + Name + "\n";
+ }
+
+ Flags |= other.Flags;
+}
+
+bool OptionDescription::isAlias() const {
+ return Type == OptionType::Alias;
+}
+
+bool OptionDescription::isMultiVal() const {
+ return MultiVal > 1;
+}
+
+bool OptionDescription::isExtern() const {
+ return Flags & OptionDescriptionFlags::Extern;
+}
+void OptionDescription::setExtern() {
+ Flags |= OptionDescriptionFlags::Extern;
+}
+
+bool OptionDescription::isRequired() const {
+ return Flags & OptionDescriptionFlags::Required;
+}
+void OptionDescription::setRequired() {
+ Flags |= OptionDescriptionFlags::Required;
+}
+
+bool OptionDescription::isOneOrMore() const {
+ return Flags & OptionDescriptionFlags::OneOrMore;
+}
+void OptionDescription::setOneOrMore() {
+ Flags |= OptionDescriptionFlags::OneOrMore;
+}
+
+bool OptionDescription::isZeroOrOne() const {
+ return Flags & OptionDescriptionFlags::ZeroOrOne;
+}
+void OptionDescription::setZeroOrOne() {
+ Flags |= OptionDescriptionFlags::ZeroOrOne;
+}
+
+bool OptionDescription::isHidden() const {
+ return Flags & OptionDescriptionFlags::Hidden;
+}
+void OptionDescription::setHidden() {
+ Flags |= OptionDescriptionFlags::Hidden;
+}
+
+bool OptionDescription::isReallyHidden() const {
+ return Flags & OptionDescriptionFlags::ReallyHidden;
+}
+void OptionDescription::setReallyHidden() {
+ Flags |= OptionDescriptionFlags::ReallyHidden;
+}
+
+const char* OptionDescription::GenTypeDeclaration() const {
+ switch (Type) {
+ case OptionType::Alias:
+ return "cl::alias";
+ case OptionType::PrefixList:
+ case OptionType::ParameterList:
+ return "cl::list<std::string>";
+ case OptionType::Switch:
+ return "cl::opt<bool>";
+ case OptionType::Parameter:
+ case OptionType::Prefix:
+ default:
+ return "cl::opt<std::string>";
+ }
+}
+
+std::string OptionDescription::GenVariableName() const {
+ const std::string& EscapedName = EscapeVariableName(Name);
+ switch (Type) {
+ case OptionType::Alias:
+ return "AutoGeneratedAlias_" + EscapedName;
+ case OptionType::PrefixList:
+ case OptionType::ParameterList:
+ return "AutoGeneratedList_" + EscapedName;
+ case OptionType::Switch:
+ return "AutoGeneratedSwitch_" + EscapedName;
+ case OptionType::Prefix:
+ case OptionType::Parameter:
+ default:
+ return "AutoGeneratedParameter_" + EscapedName;
+ }
+}
+
+/// OptionDescriptions - An OptionDescription array plus some helper
+/// functions.
+class OptionDescriptions {
+ typedef StringMap<OptionDescription> container_type;
+
+ /// Descriptions - A list of OptionDescriptions.
+ container_type Descriptions;
+
+public:
+ /// FindOption - exception-throwing wrapper for find().
+ const OptionDescription& FindOption(const std::string& OptName) const;
+
+ /// insertDescription - Insert new OptionDescription into
+ /// OptionDescriptions list
+ void InsertDescription (const OptionDescription& o);
+
+ // Support for STL-style iteration
+ typedef container_type::const_iterator const_iterator;
+ const_iterator begin() const { return Descriptions.begin(); }
+ const_iterator end() const { return Descriptions.end(); }
+};
+
+const OptionDescription&
+OptionDescriptions::FindOption(const std::string& OptName) const
+{
+ const_iterator I = Descriptions.find(OptName);
+ if (I != Descriptions.end())
+ return I->second;
+ else
+ throw OptName + ": no such option!";
+}
+
+void OptionDescriptions::InsertDescription (const OptionDescription& o)
+{
+ container_type::iterator I = Descriptions.find(o.Name);
+ if (I != Descriptions.end()) {
+ OptionDescription& D = I->second;
+ D.Merge(o);
+ }
+ else {
+ Descriptions[o.Name] = o;
+ }
+}
+
+/// HandlerTable - A base class for function objects implemented as
+/// 'tables of handlers'.
+template <class T>
+class HandlerTable {
+protected:
+ // Implementation details.
+
+ /// Handler -
+ typedef void (T::* Handler) (const DagInit*);
+ /// HandlerMap - A map from property names to property handlers
+ typedef StringMap<Handler> HandlerMap;
+
+ static HandlerMap Handlers_;
+ static bool staticMembersInitialized_;
+
+ T* childPtr;
+public:
+
+ HandlerTable(T* cp) : childPtr(cp)
+ {}
+
+ /// operator() - Just forwards to the corresponding property
+ /// handler.
+ void operator() (Init* i) {
+ const DagInit& property = InitPtrToDag(i);
+ const std::string& property_name = property.getOperator()->getAsString();
+ typename HandlerMap::iterator method = Handlers_.find(property_name);
+
+ if (method != Handlers_.end()) {
+ Handler h = method->second;
+ (childPtr->*h)(&property);
+ }
+ else {
+ throw "No handler found for property " + property_name + "!";
+ }
+ }
+
+ void AddHandler(const char* Property, Handler Handl) {
+ Handlers_[Property] = Handl;
+ }
+};
+
+template <class T> typename HandlerTable<T>::HandlerMap
+HandlerTable<T>::Handlers_;
+template <class T> bool HandlerTable<T>::staticMembersInitialized_ = false;
+
+
+/// CollectOptionProperties - Function object for iterating over an
+/// option property list.
+class CollectOptionProperties : public HandlerTable<CollectOptionProperties> {
+private:
+
+ /// optDescs_ - OptionDescriptions table. This is where the
+ /// information is stored.
+ OptionDescription& optDesc_;
+
+public:
+
+ explicit CollectOptionProperties(OptionDescription& OD)
+ : HandlerTable<CollectOptionProperties>(this), optDesc_(OD)
+ {
+ if (!staticMembersInitialized_) {
+ AddHandler("extern", &CollectOptionProperties::onExtern);
+ AddHandler("help", &CollectOptionProperties::onHelp);
+ AddHandler("hidden", &CollectOptionProperties::onHidden);
+ AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
+ AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
+ AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
+ AddHandler("required", &CollectOptionProperties::onRequired);
+ AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne);
+
+ staticMembersInitialized_ = true;
+ }
+ }
+
+private:
+
+ /// Option property handlers --
+ /// Methods that handle option properties such as (help) or (hidden).
+
+ void onExtern (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ optDesc_.setExtern();
+ }
+
+ void onHelp (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ optDesc_.Help = InitPtrToString(d->getArg(0));
+ }
+
+ void onHidden (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ optDesc_.setHidden();
+ }
+
+ void onReallyHidden (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ optDesc_.setReallyHidden();
+ }
+
+ void onRequired (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ if (optDesc_.isOneOrMore())
+ throw std::string("An option can't have both (required) "
+ "and (one_or_more) properties!");
+ optDesc_.setRequired();
+ }
+
+ void onOneOrMore (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ if (optDesc_.isRequired() || optDesc_.isZeroOrOne())
+ throw std::string("Only one of (required), (zero_or_one) or "
+ "(one_or_more) properties is allowed!");
+ if (!OptionType::IsList(optDesc_.Type))
+ llvm::cerr << "Warning: specifying the 'one_or_more' property "
+ "on a non-list option will have no effect.\n";
+ optDesc_.setOneOrMore();
+ }
+
+ void onZeroOrOne (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ if (optDesc_.isRequired() || optDesc_.isOneOrMore())
+ throw std::string("Only one of (required), (zero_or_one) or "
+ "(one_or_more) properties is allowed!");
+ if (!OptionType::IsList(optDesc_.Type))
+ llvm::cerr << "Warning: specifying the 'zero_or_one' property"
+ "on a non-list option will have no effect.\n";
+ optDesc_.setZeroOrOne();
+ }
+
+ void onMultiVal (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ int val = InitPtrToInt(d->getArg(0));
+ if (val < 2)
+ throw std::string("Error in the 'multi_val' property: "
+ "the value must be greater than 1!");
+ if (!OptionType::IsList(optDesc_.Type))
+ throw std::string("The multi_val property is valid only "
+ "on list options!");
+ optDesc_.MultiVal = val;
+ }
+
+};
+
+/// AddOption - A function object that is applied to every option
+/// description. Used by CollectOptionDescriptions.
+class AddOption {
+private:
+ OptionDescriptions& OptDescs_;
+
+public:
+ explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
+ {}
+
+ void operator()(const Init* i) {
+ const DagInit& d = InitPtrToDag(i);
+ checkNumberOfArguments(&d, 1);
+
+ const OptionType::OptionType Type =
+ stringToOptionType(d.getOperator()->getAsString());
+ const std::string& Name = InitPtrToString(d.getArg(0));
+
+ OptionDescription OD(Type, Name);
+
+ if (!OD.isExtern())
+ checkNumberOfArguments(&d, 2);
+
+ if (OD.isAlias()) {
+ // Aliases store the aliased option name in the 'Help' field.
+ OD.Help = InitPtrToString(d.getArg(1));
+ }
+ else if (!OD.isExtern()) {
+ processOptionProperties(&d, OD);
+ }
+ OptDescs_.InsertDescription(OD);
+ }
+
+private:
+ /// processOptionProperties - Go through the list of option
+ /// properties and call a corresponding handler for each.
+ static void processOptionProperties (const DagInit* d, OptionDescription& o) {
+ checkNumberOfArguments(d, 2);
+ DagInit::const_arg_iterator B = d->arg_begin();
+ // Skip the first argument: it's always the option name.
+ ++B;
+ std::for_each(B, d->arg_end(), CollectOptionProperties(o));
+ }
+
+};
+
+/// CollectOptionDescriptions - Collects option properties from all
+/// OptionLists.
+void CollectOptionDescriptions (RecordVector::const_iterator B,
+ RecordVector::const_iterator E,
+ OptionDescriptions& OptDescs)
+{
+ // For every OptionList:
+ for (; B!=E; ++B) {
+ RecordVector::value_type T = *B;
+ // Throws an exception if the value does not exist.
+ ListInit* PropList = T->getValueAsListInit("options");
+
+ // For every option description in this list:
+ // collect the information and
+ std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
+ }
+}
+
+// Tool information record
+
+namespace ToolFlags {
+ enum ToolFlags { Join = 0x1, Sink = 0x2 };
+}
+
+struct ToolDescription : public RefCountedBase<ToolDescription> {
+ std::string Name;
+ Init* CmdLine;
+ Init* Actions;
+ StrVector InLanguage;
+ std::string OutLanguage;
+ std::string OutputSuffix;
+ unsigned Flags;
+
+ // Various boolean properties
+ void setSink() { Flags |= ToolFlags::Sink; }
+ bool isSink() const { return Flags & ToolFlags::Sink; }
+ void setJoin() { Flags |= ToolFlags::Join; }
+ bool isJoin() const { return Flags & ToolFlags::Join; }
+
+ // Default ctor here is needed because StringMap can only store
+ // DefaultConstructible objects
+ ToolDescription() : CmdLine(0), Actions(0), Flags(0) {}
+ ToolDescription (const std::string& n)
+ : Name(n), CmdLine(0), Actions(0), Flags(0)
+ {}
+};
+
+/// ToolDescriptions - A list of Tool information records.
+typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
+
+
+/// CollectToolProperties - Function object for iterating over a list of
+/// tool property records.
+class CollectToolProperties : public HandlerTable<CollectToolProperties> {
+private:
+
+ /// toolDesc_ - Properties of the current Tool. This is where the
+ /// information is stored.
+ ToolDescription& toolDesc_;
+
+public:
+
+ explicit CollectToolProperties (ToolDescription& d)
+ : HandlerTable<CollectToolProperties>(this) , toolDesc_(d)
+ {
+ if (!staticMembersInitialized_) {
+
+ AddHandler("actions", &CollectToolProperties::onActions);
+ AddHandler("cmd_line", &CollectToolProperties::onCmdLine);
+ AddHandler("in_language", &CollectToolProperties::onInLanguage);
+ AddHandler("join", &CollectToolProperties::onJoin);
+ AddHandler("out_language", &CollectToolProperties::onOutLanguage);
+ AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix);
+ AddHandler("sink", &CollectToolProperties::onSink);
+
+ staticMembersInitialized_ = true;
+ }
+ }
+
+private:
+
+ /// Property handlers --
+ /// Functions that extract information about tool properties from
+ /// DAG representation.
+
+ void onActions (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ Init* Case = d->getArg(0);
+ if (typeid(*Case) != typeid(DagInit) ||
+ static_cast<DagInit*>(Case)->getOperator()->getAsString() != "case")
+ throw
+ std::string("The argument to (actions) should be a 'case' construct!");
+ toolDesc_.Actions = Case;
+ }
+
+ void onCmdLine (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ toolDesc_.CmdLine = d->getArg(0);
+ }
+
+ void onInLanguage (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ Init* arg = d->getArg(0);
+
+ // Find out the argument's type.
+ if (typeid(*arg) == typeid(StringInit)) {
+ // It's a string.
+ toolDesc_.InLanguage.push_back(InitPtrToString(arg));
+ }
+ else {
+ // It's a list.
+ const ListInit& lst = InitPtrToList(arg);
+ StrVector& out = toolDesc_.InLanguage;
+
+ // Copy strings to the output vector.
+ for (ListInit::const_iterator B = lst.begin(), E = lst.end();
+ B != E; ++B) {
+ out.push_back(InitPtrToString(*B));
+ }
+
+ // Remove duplicates.
+ std::sort(out.begin(), out.end());
+ StrVector::iterator newE = std::unique(out.begin(), out.end());
+ out.erase(newE, out.end());
+ }
+ }
+
+ void onJoin (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ toolDesc_.setJoin();
+ }
+
+ void onOutLanguage (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ toolDesc_.OutLanguage = InitPtrToString(d->getArg(0));
+ }
+
+ void onOutputSuffix (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0));
+ }
+
+ void onSink (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ toolDesc_.setSink();
+ }
+
+};
+
+/// CollectToolDescriptions - Gather information about tool properties
+/// from the parsed TableGen data (basically a wrapper for the
+/// CollectToolProperties function object).
+void CollectToolDescriptions (RecordVector::const_iterator B,
+ RecordVector::const_iterator E,
+ ToolDescriptions& ToolDescs)
+{
+ // Iterate over a properties list of every Tool definition
+ for (;B!=E;++B) {
+ const Record* T = *B;
+ // Throws an exception if the value does not exist.
+ ListInit* PropList = T->getValueAsListInit("properties");
+
+ IntrusiveRefCntPtr<ToolDescription>
+ ToolDesc(new ToolDescription(T->getName()));
+
+ std::for_each(PropList->begin(), PropList->end(),
+ CollectToolProperties(*ToolDesc));
+ ToolDescs.push_back(ToolDesc);
+ }
+}
+
+/// FillInEdgeVector - Merge all compilation graph definitions into
+/// one single edge list.
+void FillInEdgeVector(RecordVector::const_iterator B,
+ RecordVector::const_iterator E, RecordVector& Out) {
+ for (; B != E; ++B) {
+ const ListInit* edges = (*B)->getValueAsListInit("edges");
+
+ for (unsigned i = 0; i < edges->size(); ++i)
+ Out.push_back(edges->getElementAsRecord(i));
+ }
+}
+
+/// CalculatePriority - Calculate the priority of this plugin.
+int CalculatePriority(RecordVector::const_iterator B,
+ RecordVector::const_iterator E) {
+ int total = 0;
+ for (; B!=E; ++B) {
+ total += static_cast<int>((*B)->getValueAsInt("priority"));
+ }
+ return total;
+}
+
+/// NotInGraph - Helper function object for FilterNotInGraph.
+struct NotInGraph {
+private:
+ const llvm::StringSet<>& ToolsInGraph_;
+
+public:
+ NotInGraph(const llvm::StringSet<>& ToolsInGraph)
+ : ToolsInGraph_(ToolsInGraph)
+ {}
+
+ bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
+ return (ToolsInGraph_.count(x->Name) == 0);
+ }
+};
+
+/// FilterNotInGraph - Filter out from ToolDescs all Tools not
+/// mentioned in the compilation graph definition.
+void FilterNotInGraph (const RecordVector& EdgeVector,
+ ToolDescriptions& ToolDescs) {
+
+ // List all tools mentioned in the graph.
+ llvm::StringSet<> ToolsInGraph;
+
+ for (RecordVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+
+ const Record* Edge = *B;
+ const std::string& NodeA = Edge->getValueAsString("a");
+ const std::string& NodeB = Edge->getValueAsString("b");
+
+ if (NodeA != "root")
+ ToolsInGraph.insert(NodeA);
+ ToolsInGraph.insert(NodeB);
+ }
+
+ // Filter ToolPropertiesList.
+ ToolDescriptions::iterator new_end =
+ std::remove_if(ToolDescs.begin(), ToolDescs.end(),
+ NotInGraph(ToolsInGraph));
+ ToolDescs.erase(new_end, ToolDescs.end());
+}
+
+/// FillInToolToLang - Fills in two tables that map tool names to
+/// (input, output) languages. Helper function used by TypecheckGraph().
+void FillInToolToLang (const ToolDescriptions& ToolDescs,
+ StringMap<StringSet<> >& ToolToInLang,
+ StringMap<std::string>& ToolToOutLang) {
+ for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
+ E = ToolDescs.end(); B != E; ++B) {
+ const ToolDescription& D = *(*B);
+ for (StrVector::const_iterator B = D.InLanguage.begin(),
+ E = D.InLanguage.end(); B != E; ++B)
+ ToolToInLang[D.Name].insert(*B);
+ ToolToOutLang[D.Name] = D.OutLanguage;
+ }
+}
+
+/// TypecheckGraph - Check that names for output and input languages
+/// on all edges do match. This doesn't do much when the information
+/// about the whole graph is not available (i.e. when compiling most
+/// plugins).
+void TypecheckGraph (const RecordVector& EdgeVector,
+ const ToolDescriptions& ToolDescs) {
+ StringMap<StringSet<> > ToolToInLang;
+ StringMap<std::string> ToolToOutLang;
+
+ FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
+ StringMap<std::string>::iterator IAE = ToolToOutLang.end();
+ StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
+
+ for (RecordVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+ const Record* Edge = *B;
+ const std::string& NodeA = Edge->getValueAsString("a");
+ const std::string& NodeB = Edge->getValueAsString("b");
+ StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
+ StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
+
+ if (NodeA != "root") {
+ if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
+ throw "Edge " + NodeA + "->" + NodeB
+ + ": output->input language mismatch";
+ }
+
+ if (NodeB == "root")
+ throw std::string("Edges back to the root are not allowed!");
+ }
+}
+
+/// WalkCase - Walks the 'case' expression DAG and invokes
+/// TestCallback on every test, and StatementCallback on every
+/// statement. Handles 'case' nesting, but not the 'and' and 'or'
+/// combinators.
+// TODO: Re-implement EmitCaseConstructHandler on top of this function?
+template <typename F1, typename F2>
+void WalkCase(Init* Case, F1 TestCallback, F2 StatementCallback) {
+ const DagInit& d = InitPtrToDag(Case);
+ bool even = false;
+ for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
+ B != E; ++B) {
+ Init* arg = *B;
+ if (even && dynamic_cast<DagInit*>(arg)
+ && static_cast<DagInit*>(arg)->getOperator()->getAsString() == "case")
+ WalkCase(arg, TestCallback, StatementCallback);
+ else if (!even)
+ TestCallback(arg);
+ else
+ StatementCallback(arg);
+ even = !even;
+ }
+}
+
+/// ExtractOptionNames - A helper function object used by
+/// CheckForSuperfluousOptions() to walk the 'case' DAG.
+class ExtractOptionNames {
+ llvm::StringSet<>& OptionNames_;
+
+ void processDag(const Init* Statement) {
+ const DagInit& Stmt = InitPtrToDag(Statement);
+ const std::string& ActionName = Stmt.getOperator()->getAsString();
+ if (ActionName == "forward" || ActionName == "forward_as" ||
+ ActionName == "unpack_values" || ActionName == "switch_on" ||
+ ActionName == "parameter_equals" || ActionName == "element_in_list" ||
+ ActionName == "not_empty" || ActionName == "empty") {
+ checkNumberOfArguments(&Stmt, 1);
+ const std::string& Name = InitPtrToString(Stmt.getArg(0));
+ OptionNames_.insert(Name);
+ }
+ else if (ActionName == "and" || ActionName == "or") {
+ for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
+ this->processDag(Stmt.getArg(i));
+ }
+ }
+ }
+
+public:
+ ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
+ {}
+
+ void operator()(const Init* Statement) {
+ if (typeid(*Statement) == typeid(ListInit)) {
+ const ListInit& DagList = *static_cast<const ListInit*>(Statement);
+ for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
+ B != E; ++B)
+ this->processDag(*B);
+ }
+ else {
+ this->processDag(Statement);
+ }
+ }
+};
+
+/// CheckForSuperfluousOptions - Check that there are no side
+/// effect-free options (specified only in the OptionList). Otherwise,
+/// output a warning.
+void CheckForSuperfluousOptions (const RecordVector& Edges,
+ const ToolDescriptions& ToolDescs,
+ const OptionDescriptions& OptDescs) {
+ llvm::StringSet<> nonSuperfluousOptions;
+
+ // Add all options mentioned in the ToolDesc.Actions to the set of
+ // non-superfluous options.
+ for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
+ E = ToolDescs.end(); B != E; ++B) {
+ const ToolDescription& TD = *(*B);
+ ExtractOptionNames Callback(nonSuperfluousOptions);
+ if (TD.Actions)
+ WalkCase(TD.Actions, Callback, Callback);
+ }
+
+ // Add all options mentioned in the 'case' clauses of the
+ // OptionalEdges of the compilation graph to the set of
+ // non-superfluous options.
+ for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end();
+ B != E; ++B) {
+ const Record* Edge = *B;
+ DagInit* Weight = Edge->getValueAsDag("weight");
+
+ if (!isDagEmpty(Weight))
+ WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
+ }
+
+ // Check that all options in OptDescs belong to the set of
+ // non-superfluous options.
+ for (OptionDescriptions::const_iterator B = OptDescs.begin(),
+ E = OptDescs.end(); B != E; ++B) {
+ const OptionDescription& Val = B->second;
+ if (!nonSuperfluousOptions.count(Val.Name)
+ && Val.Type != OptionType::Alias)
+ llvm::cerr << "Warning: option '-" << Val.Name << "' has no effect! "
+ "Probable cause: this option is specified only in the OptionList.\n";
+ }
+}
+
+/// EmitCaseTest1Arg - Helper function used by
+/// EmitCaseConstructHandler.
+bool EmitCaseTest1Arg(const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ checkNumberOfArguments(&d, 1);
+ const std::string& OptName = InitPtrToString(d.getArg(0));
+
+ if (TestName == "switch_on") {
+ const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
+ if (!OptionType::IsSwitch(OptDesc.Type))
+ throw OptName + ": incorrect option type - should be a switch!";
+ O << OptDesc.GenVariableName();
+ return true;
+ } else if (TestName == "input_languages_contain") {
+ O << "InLangs.count(\"" << OptName << "\") != 0";
+ return true;
+ } else if (TestName == "in_language") {
+ // This works only for single-argument Tool::GenerateAction. Join
+ // tools can process several files in different languages simultaneously.
+
+ // TODO: make this work with Edge::Weight (if possible).
+ O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
+ return true;
+ } else if (TestName == "not_empty" || TestName == "empty") {
+ const char* Test = (TestName == "empty") ? "" : "!";
+
+ if (OptName == "o") {
+ O << Test << "OutputFilename.empty()";
+ return true;
+ }
+ else {
+ const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
+ if (OptionType::IsSwitch(OptDesc.Type))
+ throw OptName
+ + ": incorrect option type - should be a list or parameter!";
+ O << Test << OptDesc.GenVariableName() << ".empty()";
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/// EmitCaseTest2Args - Helper function used by
+/// EmitCaseConstructHandler.
+bool EmitCaseTest2Args(const std::string& TestName,
+ const DagInit& d,
+ const char* IndentLevel,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ checkNumberOfArguments(&d, 2);
+ const std::string& OptName = InitPtrToString(d.getArg(0));
+ const std::string& OptArg = InitPtrToString(d.getArg(1));
+ const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
+
+ if (TestName == "parameter_equals") {
+ if (!OptionType::IsParameter(OptDesc.Type))
+ throw OptName + ": incorrect option type - should be a parameter!";
+ O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
+ return true;
+ }
+ else if (TestName == "element_in_list") {
+ if (!OptionType::IsList(OptDesc.Type))
+ throw OptName + ": incorrect option type - should be a list!";
+ const std::string& VarName = OptDesc.GenVariableName();
+ O << "std::find(" << VarName << ".begin(),\n"
+ << IndentLevel << Indent1 << VarName << ".end(), \""
+ << OptArg << "\") != " << VarName << ".end()";
+ return true;
+ }
+
+ return false;
+}
+
+// Forward declaration.
+// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
+void EmitCaseTest(const DagInit& d, const char* IndentLevel,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O);
+
+/// EmitLogicalOperationTest - Helper function used by
+/// EmitCaseConstructHandler.
+void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
+ const char* IndentLevel,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ O << '(';
+ for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
+ const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
+ EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
+ if (j != NumArgs - 1)
+ O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " (";
+ else
+ O << ')';
+ }
+}
+
+/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
+void EmitCaseTest(const DagInit& d, const char* IndentLevel,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ const std::string& TestName = d.getOperator()->getAsString();
+
+ if (TestName == "and")
+ EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
+ else if (TestName == "or")
+ EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
+ else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
+ return;
+ else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
+ return;
+ else
+ throw TestName + ": unknown edge property!";
+}
+
+// Emit code that handles the 'case' construct.
+// Takes a function object that should emit code for every case clause.
+// Callback's type is
+// void F(Init* Statement, const char* IndentLevel, std::ostream& O).
+template <typename F>
+void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel,
+ F Callback, bool EmitElseIf,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ const DagInit* d = &InitPtrToDag(Dag);
+ if (d->getOperator()->getAsString() != "case")
+ throw std::string("EmitCaseConstructHandler should be invoked"
+ " only on 'case' expressions!");
+
+ unsigned numArgs = d->getNumArgs();
+ if (d->getNumArgs() < 2)
+ throw "There should be at least one clause in the 'case' expression:\n"
+ + d->getAsString();
+
+ for (unsigned i = 0; i != numArgs; ++i) {
+ const DagInit& Test = InitPtrToDag(d->getArg(i));
+
+ // Emit the test.
+ if (Test.getOperator()->getAsString() == "default") {
+ if (i+2 != numArgs)
+ throw std::string("The 'default' clause should be the last in the"
+ "'case' construct!");
+ O << IndentLevel << "else {\n";
+ }
+ else {
+ O << IndentLevel << ((i != 0 && EmitElseIf) ? "else if (" : "if (");
+ EmitCaseTest(Test, IndentLevel, OptDescs, O);
+ O << ") {\n";
+ }
+
+ // Emit the corresponding statement.
+ ++i;
+ if (i == numArgs)
+ throw "Case construct handler: no corresponding action "
+ "found for the test " + Test.getAsString() + '!';
+
+ Init* arg = d->getArg(i);
+ const DagInit* nd = dynamic_cast<DagInit*>(arg);
+ if (nd && (nd->getOperator()->getAsString() == "case")) {
+ // Handle the nested 'case'.
+ EmitCaseConstructHandler(nd, (std::string(IndentLevel) + Indent1).c_str(),
+ Callback, EmitElseIf, OptDescs, O);
+ }
+ else {
+ Callback(arg, (std::string(IndentLevel) + Indent1).c_str(), O);
+ }
+ O << IndentLevel << "}\n";
+ }
+}
+
+/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to
+/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] .
+/// Helper function used by EmitCmdLineVecFill and.
+void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
+ const char* Delimiters = " \t\n\v\f\r";
+ enum TokenizerState
+ { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
+ cur_st = Normal;
+ Out.push_back("");
+
+ std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
+ E = CmdLine.size();
+ if (B == std::string::npos)
+ throw "Empty command-line string!";
+ for (; B != E; ++B) {
+ char cur_ch = CmdLine[B];
+
+ switch (cur_st) {
+ case Normal:
+ if (cur_ch == '$') {
+ cur_st = SpecialCommand;
+ break;
+ }
+ if (oneOf(Delimiters, cur_ch)) {
+ // Skip whitespace
+ B = CmdLine.find_first_not_of(Delimiters, B);
+ if (B == std::string::npos) {
+ B = E-1;
+ continue;
+ }
+ --B;
+ Out.push_back("");
+ continue;
+ }
+ break;
+
+
+ case SpecialCommand:
+ if (oneOf(Delimiters, cur_ch)) {
+ cur_st = Normal;
+ Out.push_back("");
+ continue;
+ }
+ if (cur_ch == '(') {
+ Out.push_back("");
+ cur_st = InsideSpecialCommand;
+ continue;
+ }
+ break;
+
+ case InsideSpecialCommand:
+ if (oneOf(Delimiters, cur_ch)) {
+ continue;
+ }
+ if (cur_ch == '\'') {
+ cur_st = InsideQuotationMarks;
+ Out.push_back("");
+ continue;
+ }
+ if (cur_ch == ')') {
+ cur_st = Normal;
+ Out.push_back("");
+ }
+ if (cur_ch == ',') {
+ continue;
+ }
+
+ break;
+
+ case InsideQuotationMarks:
+ if (cur_ch == '\'') {
+ cur_st = InsideSpecialCommand;
+ continue;
+ }
+ break;
+ }
+
+ Out.back().push_back(cur_ch);
+ }
+}
+
+/// SubstituteSpecialCommands - Perform string substitution for $CALL
+/// and $ENV. Helper function used by EmitCmdLineVecFill().
+StrVector::const_iterator SubstituteSpecialCommands
+(StrVector::const_iterator Pos, StrVector::const_iterator End, std::ostream& O)
+{
+
+ const std::string& cmd = *Pos;
+
+ if (cmd == "$CALL") {
+ checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
+ const std::string& CmdName = *Pos;
+
+ if (CmdName == ")")
+ throw std::string("$CALL invocation: empty argument list!");
+
+ O << "hooks::";
+ O << CmdName << "(";
+
+
+ bool firstIteration = true;
+ while (true) {
+ checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
+ const std::string& Arg = *Pos;
+ assert(Arg.size() != 0);
+
+ if (Arg[0] == ')')
+ break;
+
+ if (firstIteration)
+ firstIteration = false;
+ else
+ O << ", ";
+
+ O << '"' << Arg << '"';
+ }
+
+ O << ')';
+
+ }
+ else if (cmd == "$ENV") {
+ checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
+ const std::string& EnvName = *Pos;
+
+ if (EnvName == ")")
+ throw "$ENV invocation: empty argument list!";
+
+ O << "checkCString(std::getenv(\"";
+ O << EnvName;
+ O << "\"))";
+
+ checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
+ }
+ else {
+ throw "Unknown special command: " + cmd;
+ }
+
+ const std::string& Leftover = *Pos;
+ assert(Leftover.at(0) == ')');
+ if (Leftover.size() != 1)
+ O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
+
+ return Pos;
+}
+
+/// EmitCmdLineVecFill - Emit code that fills in the command line
+/// vector. Helper function used by EmitGenerateActionMethod().
+void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
+ bool IsJoin, const char* IndentLevel,
+ std::ostream& O) {
+ StrVector StrVec;
+ TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
+
+ if (StrVec.empty())
+ throw "Tool " + ToolName + " has empty command line!";
+
+ StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
+
+ // If there is a hook invocation on the place of the first command, skip it.
+ assert(!StrVec[0].empty());
+ if (StrVec[0][0] == '$') {
+ while (I != E && (*I)[0] != ')' )
+ ++I;
+
+ // Skip the ')' symbol.
+ ++I;
+ }
+ else {
+ ++I;
+ }
+
+ for (; I != E; ++I) {
+ const std::string& cmd = *I;
+ assert(!cmd.empty());
+ O << IndentLevel;
+ if (cmd.at(0) == '$') {
+ if (cmd == "$INFILE") {
+ if (IsJoin)
+ O << "for (PathVector::const_iterator B = inFiles.begin()"
+ << ", E = inFiles.end();\n"
+ << IndentLevel << "B != E; ++B)\n"
+ << IndentLevel << Indent1 << "vec.push_back(B->toString());\n";
+ else
+ O << "vec.push_back(inFile.toString());\n";
+ }
+ else if (cmd == "$OUTFILE") {
+ O << "vec.push_back(out_file);\n";
+ }
+ else {
+ O << "vec.push_back(";
+ I = SubstituteSpecialCommands(I, E, O);
+ O << ");\n";
+ }
+ }
+ else {
+ O << "vec.push_back(\"" << cmd << "\");\n";
+ }
+ }
+ O << IndentLevel << "cmd = ";
+
+ if (StrVec[0][0] == '$')
+ SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O);
+ else
+ O << '"' << StrVec[0] << '"';
+ O << ";\n";
+}
+
+/// EmitCmdLineVecFillCallback - A function object wrapper around
+/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an
+/// argument to EmitCaseConstructHandler().
+class EmitCmdLineVecFillCallback {
+ bool IsJoin;
+ const std::string& ToolName;
+ public:
+ EmitCmdLineVecFillCallback(bool J, const std::string& TN)
+ : IsJoin(J), ToolName(TN) {}
+
+ void operator()(const Init* Statement, const char* IndentLevel,
+ std::ostream& O) const
+ {
+ EmitCmdLineVecFill(Statement, ToolName, IsJoin,
+ IndentLevel, O);
+ }
+};
+
+/// EmitForwardOptionPropertyHandlingCode - Helper function used to
+/// implement EmitActionHandler. Emits code for
+/// handling the (forward) and (forward_as) option properties.
+void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
+ const char* Indent,
+ const std::string& NewName,
+ std::ostream& O) {
+ const std::string& Name = NewName.empty()
+ ? ("-" + D.Name)
+ : NewName;
+
+ switch (D.Type) {
+ case OptionType::Switch:
+ O << Indent << "vec.push_back(\"" << Name << "\");\n";
+ break;
+ case OptionType::Parameter:
+ O << Indent << "vec.push_back(\"" << Name << "\");\n";
+ O << Indent << "vec.push_back(" << D.GenVariableName() << ");\n";
+ break;
+ case OptionType::Prefix:
+ O << Indent << "vec.push_back(\"" << Name << "\" + "
+ << D.GenVariableName() << ");\n";
+ break;
+ case OptionType::PrefixList:
+ O << Indent << "for (" << D.GenTypeDeclaration()
+ << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
+ << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"
+ << Indent << Indent1 << "vec.push_back(\"" << Name << "\" + "
+ << "*B);\n"
+ << Indent << Indent1 << "++B;\n";
+
+ for (int i = 1, j = D.MultiVal; i < j; ++i) {
+ O << Indent << Indent1 << "vec.push_back(*B);\n"
+ << Indent << Indent1 << "++B;\n";
+ }
+
+ O << Indent << "}\n";
+ break;
+ case OptionType::ParameterList:
+ O << Indent << "for (" << D.GenTypeDeclaration()
+ << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
+ << Indent << "E = " << D.GenVariableName()
+ << ".end() ; B != E;) {\n"
+ << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n";
+
+ for (int i = 0, j = D.MultiVal; i < j; ++i) {
+ O << Indent << Indent1 << "vec.push_back(*B);\n"
+ << Indent << Indent1 << "++B;\n";
+ }
+
+ O << Indent << "}\n";
+ break;
+ case OptionType::Alias:
+ default:
+ throw std::string("Aliases are not allowed in tool option descriptions!");
+ }
+}
+
+/// EmitActionHandler - Emit code that handles actions. Used by
+/// EmitGenerateActionMethod() as an argument to
+/// EmitCaseConstructHandler().
+class EmitActionHandler {
+ const OptionDescriptions& OptDescs;
+
+ void processActionDag(const Init* Statement, const char* IndentLevel,
+ std::ostream& O) const
+ {
+ const DagInit& Dag = InitPtrToDag(Statement);
+ const std::string& ActionName = Dag.getOperator()->getAsString();
+
+ if (ActionName == "append_cmd") {
+ checkNumberOfArguments(&Dag, 1);
+ const std::string& Cmd = InitPtrToString(Dag.getArg(0));
+ StrVector Out;
+ llvm::SplitString(Cmd, Out);
+
+ for (StrVector::const_iterator B = Out.begin(), E = Out.end();
+ B != E; ++B)
+ O << IndentLevel << "vec.push_back(\"" << *B << "\");\n";
+ }
+ else if (ActionName == "error") {
+ O << IndentLevel << "throw std::runtime_error(\"" <<
+ (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0))
+ : "Unknown error!")
+ << "\");\n";
+ }
+ else if (ActionName == "forward") {
+ checkNumberOfArguments(&Dag, 1);
+ const std::string& Name = InitPtrToString(Dag.getArg(0));
+ EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
+ IndentLevel, "", O);
+ }
+ else if (ActionName == "forward_as") {
+ checkNumberOfArguments(&Dag, 2);
+ const std::string& Name = InitPtrToString(Dag.getArg(0));
+ const std::string& NewName = InitPtrToString(Dag.getArg(1));
+ EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
+ IndentLevel, NewName, O);
+ }
+ else if (ActionName == "output_suffix") {
+ checkNumberOfArguments(&Dag, 1);
+ const std::string& OutSuf = InitPtrToString(Dag.getArg(0));
+ O << IndentLevel << "output_suffix = \"" << OutSuf << "\";\n";
+ }
+ else if (ActionName == "stop_compilation") {
+ O << IndentLevel << "stop_compilation = true;\n";
+ }
+ else if (ActionName == "unpack_values") {
+ checkNumberOfArguments(&Dag, 1);
+ const std::string& Name = InitPtrToString(Dag.getArg(0));
+ const OptionDescription& D = OptDescs.FindOption(Name);
+
+ if (D.isMultiVal())
+ throw std::string("Can't use unpack_values with multi-valued options!");
+
+ if (OptionType::IsList(D.Type)) {
+ O << IndentLevel << "for (" << D.GenTypeDeclaration()
+ << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
+ << IndentLevel << "E = " << D.GenVariableName()
+ << ".end(); B != E; ++B)\n"
+ << IndentLevel << Indent1 << "llvm::SplitString(*B, vec, \",\");\n";
+ }
+ else if (OptionType::IsParameter(D.Type)){
+ O << Indent3 << "llvm::SplitString("
+ << D.GenVariableName() << ", vec, \",\");\n";
+ }
+ else {
+ throw "Option '" + D.Name +
+ "': switches can't have the 'unpack_values' property!";
+ }
+ }
+ else {
+ throw "Unknown action name: " + ActionName + "!";
+ }
+ }
+ public:
+ EmitActionHandler(const OptionDescriptions& OD)
+ : OptDescs(OD) {}
+
+ void operator()(const Init* Statement, const char* IndentLevel,
+ std::ostream& O) const
+ {
+ if (typeid(*Statement) == typeid(ListInit)) {
+ const ListInit& DagList = *static_cast<const ListInit*>(Statement);
+ for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
+ B != E; ++B)
+ this->processActionDag(*B, IndentLevel, O);
+ }
+ else {
+ this->processActionDag(Statement, IndentLevel, O);
+ }
+ }
+};
+
+// EmitGenerateActionMethod - Emit one of two versions of the
+// Tool::GenerateAction() method.
+void EmitGenerateActionMethod (const ToolDescription& D,
+ const OptionDescriptions& OptDescs,
+ bool IsJoin, std::ostream& O) {
+ if (IsJoin)
+ O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
+ else
+ O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
+
+ O << Indent2 << "bool HasChildren,\n"
+ << Indent2 << "const llvm::sys::Path& TempDir,\n"
+ << Indent2 << "const InputLanguagesSet& InLangs,\n"
+ << Indent2 << "const LanguageMap& LangMap) const\n"
+ << Indent1 << "{\n"
+ << Indent2 << "std::string cmd;\n"
+ << Indent2 << "std::vector<std::string> vec;\n"
+ << Indent2 << "bool stop_compilation = !HasChildren;\n"
+ << Indent2 << "const char* output_suffix = \"" << D.OutputSuffix << "\";\n"
+ << Indent2 << "std::string out_file;\n\n";
+
+ // For every understood option, emit handling code.
+ if (D.Actions)
+ EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs),
+ false, OptDescs, O);
+
+ O << '\n' << Indent2
+ << "out_file = OutFilename(" << (IsJoin ? "sys::Path(),\n" : "inFile,\n")
+ << Indent3 << "TempDir, stop_compilation, output_suffix).toString();\n\n";
+
+ // cmd_line is either a string or a 'case' construct.
+ if (!D.CmdLine)
+ throw "Tool " + D.Name + " has no cmd_line property!";
+ else if (typeid(*D.CmdLine) == typeid(StringInit))
+ EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
+ else
+ EmitCaseConstructHandler(D.CmdLine, Indent2,
+ EmitCmdLineVecFillCallback(IsJoin, D.Name),
+ true, OptDescs, O);
+
+ // Handle the Sink property.
+ if (D.isSink()) {
+ O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
+ << Indent3 << "vec.insert(vec.end(), "
+ << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
+ << Indent2 << "}\n";
+ }
+
+ O << Indent2 << "return Action(cmd, vec, stop_compilation, out_file);\n"
+ << Indent1 << "}\n\n";
+}
+
+/// EmitGenerateActionMethods - Emit two GenerateAction() methods for
+/// a given Tool class.
+void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ if (!ToolDesc.isJoin())
+ O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
+ << Indent2 << "bool HasChildren,\n"
+ << Indent2 << "const llvm::sys::Path& TempDir,\n"
+ << Indent2 << "const InputLanguagesSet& InLangs,\n"
+ << Indent2 << "const LanguageMap& LangMap) const\n"
+ << Indent1 << "{\n"
+ << Indent2 << "throw std::runtime_error(\"" << ToolDesc.Name
+ << " is not a Join tool!\");\n"
+ << Indent1 << "}\n\n";
+ else
+ EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
+
+ EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
+}
+
+/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
+/// methods for a given Tool class.
+void EmitInOutLanguageMethods (const ToolDescription& D, std::ostream& O) {
+ O << Indent1 << "const char** InputLanguages() const {\n"
+ << Indent2 << "return InputLanguages_;\n"
+ << Indent1 << "}\n\n";
+
+ if (D.OutLanguage.empty())
+ throw "Tool " + D.Name + " has no 'out_language' property!";
+
+ O << Indent1 << "const char* OutputLanguage() const {\n"
+ << Indent2 << "return \"" << D.OutLanguage << "\";\n"
+ << Indent1 << "}\n\n";
+}
+
+/// EmitNameMethod - Emit the Name() method for a given Tool class.
+void EmitNameMethod (const ToolDescription& D, std::ostream& O) {
+ O << Indent1 << "const char* Name() const {\n"
+ << Indent2 << "return \"" << D.Name << "\";\n"
+ << Indent1 << "}\n\n";
+}
+
+/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
+/// class.
+void EmitIsJoinMethod (const ToolDescription& D, std::ostream& O) {
+ O << Indent1 << "bool IsJoin() const {\n";
+ if (D.isJoin())
+ O << Indent2 << "return true;\n";
+ else
+ O << Indent2 << "return false;\n";
+ O << Indent1 << "}\n\n";
+}
+
+/// EmitStaticMemberDefinitions - Emit static member definitions for a
+/// given Tool class.
+void EmitStaticMemberDefinitions(const ToolDescription& D, std::ostream& O) {
+ if (D.InLanguage.empty())
+ throw "Tool " + D.Name + " has no 'in_language' property!";
+
+ O << "const char* " << D.Name << "::InputLanguages_[] = {";
+ for (StrVector::const_iterator B = D.InLanguage.begin(),
+ E = D.InLanguage.end(); B != E; ++B)
+ O << '\"' << *B << "\", ";
+ O << "0};\n\n";
+}
+
+/// EmitToolClassDefinition - Emit a Tool class definition.
+void EmitToolClassDefinition (const ToolDescription& D,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ if (D.Name == "root")
+ return;
+
+ // Header
+ O << "class " << D.Name << " : public ";
+ if (D.isJoin())
+ O << "JoinTool";
+ else
+ O << "Tool";
+
+ O << "{\nprivate:\n"
+ << Indent1 << "static const char* InputLanguages_[];\n\n";
+
+ O << "public:\n";
+ EmitNameMethod(D, O);
+ EmitInOutLanguageMethods(D, O);
+ EmitIsJoinMethod(D, O);
+ EmitGenerateActionMethods(D, OptDescs, O);
+
+ // Close class definition
+ O << "};\n";
+
+ EmitStaticMemberDefinitions(D, O);
+
+}
+
+/// EmitOptionDefintions - Iterate over a list of option descriptions
+/// and emit registration code.
+void EmitOptionDefintions (const OptionDescriptions& descs,
+ bool HasSink, bool HasExterns,
+ std::ostream& O)
+{
+ std::vector<OptionDescription> Aliases;
+
+ // Emit static cl::Option variables.
+ for (OptionDescriptions::const_iterator B = descs.begin(),
+ E = descs.end(); B!=E; ++B) {
+ const OptionDescription& val = B->second;
+
+ if (val.Type == OptionType::Alias) {
+ Aliases.push_back(val);
+ continue;
+ }
+
+ if (val.isExtern())
+ O << "extern ";
+
+ O << val.GenTypeDeclaration() << ' '
+ << val.GenVariableName();
+
+ if (val.isExtern()) {
+ O << ";\n";
+ continue;
+ }
+
+ O << "(\"" << val.Name << '\"';
+
+ if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
+ O << ", cl::Prefix";
+
+ if (val.isRequired()) {
+ if (OptionType::IsList(val.Type) && !val.isMultiVal())
+ O << ", cl::OneOrMore";
+ else
+ O << ", cl::Required";
+ }
+ else if (val.isOneOrMore() && OptionType::IsList(val.Type)) {
+ O << ", cl::OneOrMore";
+ }
+ else if (val.isZeroOrOne() && OptionType::IsList(val.Type)) {
+ O << ", cl::ZeroOrOne";
+ }
+
+ if (val.isReallyHidden()) {
+ O << ", cl::ReallyHidden";
+ }
+ else if (val.isHidden()) {
+ O << ", cl::Hidden";
+ }
+
+ if (val.MultiVal > 1)
+ O << ", cl::multi_val(" << val.MultiVal << ")";
+
+ if (!val.Help.empty())
+ O << ", cl::desc(\"" << val.Help << "\")";
+
+ O << ");\n";
+ }
+
+ // Emit the aliases (they should go after all the 'proper' options).
+ for (std::vector<OptionDescription>::const_iterator
+ B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
+ const OptionDescription& val = *B;
+
+ O << val.GenTypeDeclaration() << ' '
+ << val.GenVariableName()
+ << "(\"" << val.Name << '\"';
+
+ const OptionDescription& D = descs.FindOption(val.Help);
+ O << ", cl::aliasopt(" << D.GenVariableName() << ")";
+
+ O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
+ }
+
+ // Emit the sink option.
+ if (HasSink)
+ O << (HasExterns ? "extern cl" : "cl")
+ << "::list<std::string> " << SinkOptionName
+ << (HasExterns ? ";\n" : "(cl::Sink);\n");
+
+ O << '\n';
+}
+
+/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
+void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
+{
+ // Generate code
+ O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
+
+ // Get the relevant field out of RecordKeeper
+ const Record* LangMapRecord = Records.getDef("LanguageMap");
+
+ // It is allowed for a plugin to have no language map.
+ if (LangMapRecord) {
+
+ ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
+ if (!LangsToSuffixesList)
+ throw std::string("Error in the language map definition!");
+
+ for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
+ const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
+
+ const std::string& Lang = LangToSuffixes->getValueAsString("lang");
+ const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
+
+ for (unsigned i = 0; i < Suffixes->size(); ++i)
+ O << Indent1 << "langMap[\""
+ << InitPtrToString(Suffixes->getElement(i))
+ << "\"] = \"" << Lang << "\";\n";
+ }
+ }
+
+ O << "}\n\n";
+}
+
+/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
+/// by EmitEdgeClass().
+void IncDecWeight (const Init* i, const char* IndentLevel,
+ std::ostream& O) {
+ const DagInit& d = InitPtrToDag(i);
+ const std::string& OpName = d.getOperator()->getAsString();
+
+ if (OpName == "inc_weight") {
+ O << IndentLevel << "ret += ";
+ }
+ else if (OpName == "dec_weight") {
+ O << IndentLevel << "ret -= ";
+ }
+ else if (OpName == "error") {
+ O << IndentLevel << "throw std::runtime_error(\"" <<
+ (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
+ : "Unknown error!")
+ << "\");\n";
+ return;
+ }
+
+ else
+ throw "Unknown operator in edge properties list: " + OpName + '!' +
+ "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
+
+ if (d.getNumArgs() > 0)
+ O << InitPtrToInt(d.getArg(0)) << ";\n";
+ else
+ O << "2;\n";
+
+}
+
+/// EmitEdgeClass - Emit a single Edge# class.
+void EmitEdgeClass (unsigned N, const std::string& Target,
+ DagInit* Case, const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+
+ // Class constructor.
+ O << "class Edge" << N << ": public Edge {\n"
+ << "public:\n"
+ << Indent1 << "Edge" << N << "() : Edge(\"" << Target
+ << "\") {}\n\n"
+
+ // Function Weight().
+ << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"
+ << Indent2 << "unsigned ret = 0;\n";
+
+ // Handle the 'case' construct.
+ EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
+
+ O << Indent2 << "return ret;\n"
+ << Indent1 << "};\n\n};\n\n";
+}
+
+/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
+void EmitEdgeClasses (const RecordVector& EdgeVector,
+ const OptionDescriptions& OptDescs,
+ std::ostream& O) {
+ int i = 0;
+ for (RecordVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+ const Record* Edge = *B;
+ const std::string& NodeB = Edge->getValueAsString("b");
+ DagInit* Weight = Edge->getValueAsDag("weight");
+
+ if (!isDagEmpty(Weight))
+ EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
+ ++i;
+ }
+}
+
+/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph()
+/// function.
+void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
+ const ToolDescriptions& ToolDescs,
+ std::ostream& O)
+{
+ O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
+
+ for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
+ E = ToolDescs.end(); B != E; ++B)
+ O << Indent1 << "G.insertNode(new " << (*B)->Name << "());\n";
+
+ O << '\n';
+
+ // Insert edges.
+
+ int i = 0;
+ for (RecordVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+ const Record* Edge = *B;
+ const std::string& NodeA = Edge->getValueAsString("a");
+ const std::string& NodeB = Edge->getValueAsString("b");
+ DagInit* Weight = Edge->getValueAsDag("weight");
+
+ O << Indent1 << "G.insertEdge(\"" << NodeA << "\", ";
+
+ if (isDagEmpty(Weight))
+ O << "new SimpleEdge(\"" << NodeB << "\")";
+ else
+ O << "new Edge" << i << "()";
+
+ O << ");\n";
+ ++i;
+ }
+
+ O << "}\n\n";
+}
+
+/// ExtractHookNames - Extract the hook names from all instances of
+/// $CALL(HookName) in the provided command line string. Helper
+/// function used by FillInHookNames().
+class ExtractHookNames {
+ llvm::StringMap<unsigned>& HookNames_;
+public:
+ ExtractHookNames(llvm::StringMap<unsigned>& HookNames)
+ : HookNames_(HookNames) {}
+
+ void operator()(const Init* CmdLine) {
+ StrVector cmds;
+ TokenizeCmdline(InitPtrToString(CmdLine), cmds);
+ for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
+ B != E; ++B) {
+ const std::string& cmd = *B;
+
+ if (cmd == "$CALL") {
+ unsigned NumArgs = 0;
+ checkedIncrement(B, E, "Syntax error in $CALL invocation!");
+ const std::string& HookName = *B;
+
+
+ if (HookName.at(0) == ')')
+ throw "$CALL invoked with no arguments!";
+
+ while (++B != E && B->at(0) != ')') {
+ ++NumArgs;
+ }
+
+ StringMap<unsigned>::const_iterator H = HookNames_.find(HookName);
+
+ if (H != HookNames_.end() && H->second != NumArgs)
+ throw "Overloading of hooks is not allowed. Overloaded hook: "
+ + HookName;
+ else
+ HookNames_[HookName] = NumArgs;
+
+ }
+ }
+ }
+};
+
+/// FillInHookNames - Actually extract the hook names from all command
+/// line strings. Helper function used by EmitHookDeclarations().
+void FillInHookNames(const ToolDescriptions& ToolDescs,
+ llvm::StringMap<unsigned>& HookNames)
+{
+ // For all command lines:
+ for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
+ E = ToolDescs.end(); B != E; ++B) {
+ const ToolDescription& D = *(*B);
+ if (!D.CmdLine)
+ continue;
+ if (dynamic_cast<StringInit*>(D.CmdLine))
+ // This is a string.
+ ExtractHookNames(HookNames).operator()(D.CmdLine);
+ else
+ // This is a 'case' construct.
+ WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames));
+ }
+}
+
+/// EmitHookDeclarations - Parse CmdLine fields of all the tool
+/// property records and emit hook function declaration for each
+/// instance of $CALL(HookName).
+void EmitHookDeclarations(const ToolDescriptions& ToolDescs, std::ostream& O) {
+ llvm::StringMap<unsigned> HookNames;
+
+ FillInHookNames(ToolDescs, HookNames);
+ if (HookNames.empty())
+ return;
+
+ O << "namespace hooks {\n";
+ for (StringMap<unsigned>::const_iterator B = HookNames.begin(),
+ E = HookNames.end(); B != E; ++B) {
+ O << Indent1 << "std::string " << B->first() << "(";
+
+ for (unsigned i = 0, j = B->second; i < j; ++i) {
+ O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
+ }
+
+ O <<");\n";
+ }
+ O << "}\n\n";
+}
+
+/// EmitRegisterPlugin - Emit code to register this plugin.
+void EmitRegisterPlugin(int Priority, std::ostream& O) {
+ O << "struct Plugin : public llvmc::BasePlugin {\n\n"
+ << Indent1 << "int Priority() const { return " << Priority << "; }\n\n"
+ << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n"
+ << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n"
+ << Indent1
+ << "void PopulateCompilationGraph(CompilationGraph& graph) const\n"
+ << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n"
+ << "};\n\n"
+
+ << "static llvmc::RegisterPlugin<Plugin> RP;\n\n";
+}
+
+/// EmitIncludes - Emit necessary #include directives and some
+/// additional declarations.
+void EmitIncludes(std::ostream& O) {
+ O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
+ << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
+ << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
+
+ << "#include \"llvm/ADT/StringExtras.h\"\n"
+ << "#include \"llvm/Support/CommandLine.h\"\n\n"
+
+ << "#include <cstdlib>\n"
+ << "#include <stdexcept>\n\n"
+
+ << "using namespace llvm;\n"
+ << "using namespace llvmc;\n\n"
+
+ << "extern cl::opt<std::string> OutputFilename;\n\n"
+
+ << "inline const char* checkCString(const char* s)\n"
+ << "{ return s == NULL ? \"\" : s; }\n\n";
+}
+
+
+/// PluginData - Holds all information about a plugin.
+struct PluginData {
+ OptionDescriptions OptDescs;
+ bool HasSink;
+ bool HasExterns;
+ ToolDescriptions ToolDescs;
+ RecordVector Edges;
+ int Priority;
+};
+
+/// HasSink - Go through the list of tool descriptions and check if
+/// there are any with the 'sink' property set.
+bool HasSink(const ToolDescriptions& ToolDescs) {
+ for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
+ E = ToolDescs.end(); B != E; ++B)
+ if ((*B)->isSink())
+ return true;
+
+ return false;
+}
+
+/// HasExterns - Go through the list of option descriptions and check
+/// if there are any external options.
+bool HasExterns(const OptionDescriptions& OptDescs) {
+ for (OptionDescriptions::const_iterator B = OptDescs.begin(),
+ E = OptDescs.end(); B != E; ++B)
+ if (B->second.isExtern())
+ return true;
+
+ return false;
+}
+
+/// CollectPluginData - Collect tool and option properties,
+/// compilation graph edges and plugin priority from the parse tree.
+void CollectPluginData (const RecordKeeper& Records, PluginData& Data) {
+ // Collect option properties.
+ const RecordVector& OptionLists =
+ Records.getAllDerivedDefinitions("OptionList");
+ CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(),
+ Data.OptDescs);
+
+ // Collect tool properties.
+ const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
+ CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs);
+ Data.HasSink = HasSink(Data.ToolDescs);
+ Data.HasExterns = HasExterns(Data.OptDescs);
+
+ // Collect compilation graph edges.
+ const RecordVector& CompilationGraphs =
+ Records.getAllDerivedDefinitions("CompilationGraph");
+ FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(),
+ Data.Edges);
+
+ // Calculate the priority of this plugin.
+ const RecordVector& Priorities =
+ Records.getAllDerivedDefinitions("PluginPriority");
+ Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end());
+}
+
+/// CheckPluginData - Perform some sanity checks on the collected data.
+void CheckPluginData(PluginData& Data) {
+ // Filter out all tools not mentioned in the compilation graph.
+ FilterNotInGraph(Data.Edges, Data.ToolDescs);
+
+ // Typecheck the compilation graph.
+ TypecheckGraph(Data.Edges, Data.ToolDescs);
+
+ // Check that there are no options without side effects (specified
+ // only in the OptionList).
+ CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
+
+}
+
+void EmitPluginCode(const PluginData& Data, std::ostream& O) {
+ // Emit file header.
+ EmitIncludes(O);
+
+ // Emit global option registration code.
+ EmitOptionDefintions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
+
+ // Emit hook declarations.
+ EmitHookDeclarations(Data.ToolDescs, O);
+
+ O << "namespace {\n\n";
+
+ // Emit PopulateLanguageMap() function
+ // (a language map maps from file extensions to language names).
+ EmitPopulateLanguageMap(Records, O);
+
+ // Emit Tool classes.
+ for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
+ E = Data.ToolDescs.end(); B!=E; ++B)
+ EmitToolClassDefinition(*(*B), Data.OptDescs, O);
+
+ // Emit Edge# classes.
+ EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
+
+ // Emit PopulateCompilationGraph() function.
+ EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
+
+ // Emit code for plugin registration.
+ EmitRegisterPlugin(Data.Priority, O);
+
+ O << "} // End anonymous namespace.\n";
+ // EOF
+}
+
+
+// End of anonymous namespace
+}
+
+/// run - The back-end entry point.
+void LLVMCConfigurationEmitter::run (std::ostream &O) {
+ try {
+ PluginData Data;
+
+ CollectPluginData(Records, Data);
+ CheckPluginData(Data);
+
+ EmitSourceFileHeader("LLVMC Configuration Library", O);
+ EmitPluginCode(Data, O);
+
+ } catch (std::exception& Error) {
+ throw Error.what() + std::string(" - usually this means a syntax error.");
+ }
+}
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.h b/utils/TableGen/LLVMCConfigurationEmitter.h
new file mode 100644
index 000000000000..98c4bc069560
--- /dev/null
+++ b/utils/TableGen/LLVMCConfigurationEmitter.h
@@ -0,0 +1,33 @@
+//===- LLVMCConfigurationEmitter.cpp - Generate LLVMCC config ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open
+// Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting LLVMCC configuration code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_LLVMCCONF_EMITTER_H
+#define LLVM_UTILS_TABLEGEN_LLVMCCONF_EMITTER_H
+
+#include "TableGenBackend.h"
+
+namespace llvm {
+
+ /// LLVMCConfigurationEmitter - TableGen backend that generates
+ /// configuration code for LLVMC.
+ class LLVMCConfigurationEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ public:
+ explicit LLVMCConfigurationEmitter(RecordKeeper &R) : Records(R) {}
+
+ // run - Output the asmwriter, returning true on failure.
+ void run(std::ostream &o);
+ };
+}
+
+#endif //LLVM_UTILS_TABLEGEN_LLVMCCONF_EMITTER_H
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
new file mode 100644
index 000000000000..7ea88de05591
--- /dev/null
+++ b/utils/TableGen/Makefile
@@ -0,0 +1,20 @@
+##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TOOLNAME = tblgen
+USEDLIBS = LLVMSupport.a LLVMSystem.a
+REQUIRES_EH := 1
+REQUIRES_RTTI := 1
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
new file mode 100644
index 000000000000..45804b938cb2
--- /dev/null
+++ b/utils/TableGen/Record.cpp
@@ -0,0 +1,1485 @@
+//===- Record.cpp - Record implementation ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "llvm/ADT/StringExtras.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) {
+ int64_t 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;
+}
+
+std::string BitsRecTy::getAsString() const {
+ return "bits<" + utostr(Size) + ">";
+}
+
+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) {
+ int64_t 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(UnOpInit *BO) {
+ if (BO->getOpcode() == UnOpInit::CAST) {
+ Init *L = BO->getOperand()->convertInitializerTo(this);
+ if (L == 0) return 0;
+ if (L != BO->getOperand())
+ return new UnOpInit(UnOpInit::CAST, L, new StringRecTy);
+ return BO;
+ }
+
+ return convertValue((TypedInit*)BO);
+}
+
+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, new StringRecTy);
+ return BO;
+ }
+ if (BO->getOpcode() == BinOpInit::NAMECONCAT) {
+ if (BO->getType()->getAsString() == getAsString()) {
+ 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::NAMECONCAT, L, R, new StringRecTy);
+ return BO;
+ }
+ }
+
+ return convertValue((TypedInit*)BO);
+}
+
+
+Init *StringRecTy::convertValue(TypedInit *TI) {
+ if (dynamic_cast<StringRecTy*>(TI->getType()))
+ return TI; // Accept variable if already of the right type!
+ return 0;
+}
+
+std::string ListRecTy::getAsString() const {
+ return "list<" + Ty->getAsString() + ">";
+}
+
+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(UnOpInit *BO) {
+ if (BO->getOpcode() == UnOpInit::CAST) {
+ Init *L = BO->getOperand()->convertInitializerTo(this);
+ if (L == 0) return 0;
+ if (L != BO->getOperand())
+ return new UnOpInit(UnOpInit::CAST, L, new DagRecTy);
+ return BO;
+ }
+ 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, new DagRecTy);
+ return BO;
+ }
+ if (BO->getOpcode() == BinOpInit::NAMECONCAT) {
+ if (BO->getType()->getAsString() == getAsString()) {
+ 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, new DagRecTy);
+ return BO;
+ }
+ }
+ return 0;
+}
+
+std::string RecordRecTy::getAsString() const {
+ return 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;
+}
+
+std::string BitsInit::getAsString() const {
+ //if (!printInHex(OS)) return;
+ //if (!printAsVariable(OS)) return;
+ //if (!printAsUnset(OS)) return;
+
+ std::string Result = "{ ";
+ for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
+ if (i) Result += ", ";
+ if (Init *Bit = getBit(e-i-1))
+ Result += Bit->getAsString();
+ else
+ Result += "*";
+ }
+ return Result + " }";
+}
+
+bool BitsInit::printInHex(std::ostream &OS) const {
+ // First, attempt to convert the value into an integer value...
+ int64_t 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;
+}
+
+std::string IntInit::getAsString() const {
+ return itostr(Value);
+}
+
+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] >= 64) {
+ delete BI;
+ return 0;
+ }
+ BI->setBit(i, new BitInit(Value & (INT64_C(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;
+}
+
+std::string ListInit::getAsString() const {
+ std::string Result = "[";
+ for (unsigned i = 0, e = Values.size(); i != e; ++i) {
+ if (i) Result += ", ";
+ Result += Values[i]->getAsString();
+ }
+ return Result + "]";
+}
+
+Init *OpInit::resolveBitReference(Record &R, const RecordVal *IRV,
+ unsigned Bit) {
+ Init *Folded = Fold(&R, 0);
+
+ if (Folded != this) {
+ TypedInit *Typed = dynamic_cast<TypedInit *>(Folded);
+ if (Typed) {
+ return Typed->resolveBitReference(R, IRV, Bit);
+ }
+ }
+
+ return 0;
+}
+
+Init *OpInit::resolveListElementReference(Record &R, const RecordVal *IRV,
+ unsigned Elt) {
+ Init *Folded = Fold(&R, 0);
+
+ if (Folded != this) {
+ TypedInit *Typed = dynamic_cast<TypedInit *>(Folded);
+ if (Typed) {
+ return Typed->resolveListElementReference(R, IRV, Elt);
+ }
+ }
+
+ return 0;
+}
+
+Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
+ switch (getOpcode()) {
+ default: assert(0 && "Unknown unop");
+ case CAST: {
+ StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
+ if (LHSs) {
+ std::string Name = LHSs->getValue();
+
+ // From TGParser::ParseIDValue
+ if (CurRec) {
+ if (const RecordVal *RV = CurRec->getValue(Name)) {
+ if (RV->getType() != getType()) {
+ throw "type mismatch in nameconcat";
+ }
+ return new VarInit(Name, RV->getType());
+ }
+
+ std::string TemplateArgName = CurRec->getName()+":"+Name;
+ if (CurRec->isTemplateArg(TemplateArgName)) {
+ const RecordVal *RV = CurRec->getValue(TemplateArgName);
+ assert(RV && "Template arg doesn't exist??");
+
+ if (RV->getType() != getType()) {
+ throw "type mismatch in nameconcat";
+ }
+
+ return new VarInit(TemplateArgName, RV->getType());
+ }
+ }
+
+ if (CurMultiClass) {
+ std::string MCName = CurMultiClass->Rec.getName()+"::"+Name;
+ if (CurMultiClass->Rec.isTemplateArg(MCName)) {
+ const RecordVal *RV = CurMultiClass->Rec.getValue(MCName);
+ assert(RV && "Template arg doesn't exist??");
+
+ if (RV->getType() != getType()) {
+ throw "type mismatch in nameconcat";
+ }
+
+ return new VarInit(MCName, RV->getType());
+ }
+ }
+
+ if (Record *D = Records.getDef(Name))
+ return new DefInit(D);
+
+ cerr << "Variable not defined: '" + Name + "'\n";
+ assert(0 && "Variable not found");
+ return 0;
+ }
+ break;
+ }
+ case CAR: {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ if (LHSl) {
+ if (LHSl->getSize() == 0) {
+ assert(0 && "Empty list in car");
+ return 0;
+ }
+ return LHSl->getElement(0);
+ }
+ break;
+ }
+ case CDR: {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ if (LHSl) {
+ if (LHSl->getSize() == 0) {
+ assert(0 && "Empty list in cdr");
+ return 0;
+ }
+ ListInit *Result = new ListInit(LHSl->begin()+1, LHSl->end());
+ return Result;
+ }
+ break;
+ }
+ case LNULL: {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ if (LHSl) {
+ if (LHSl->getSize() == 0) {
+ return new IntInit(1);
+ }
+ else {
+ return new IntInit(0);
+ }
+ }
+ break;
+ }
+ }
+ return this;
+}
+
+Init *UnOpInit::resolveReferences(Record &R, const RecordVal *RV) {
+ Init *lhs = LHS->resolveReferences(R, RV);
+
+ if (LHS != lhs)
+ return (new UnOpInit(getOpcode(), lhs, getType()))->Fold(&R, 0);
+ return Fold(&R, 0);
+}
+
+std::string UnOpInit::getAsString() const {
+ std::string Result;
+ switch (Opc) {
+ case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break;
+ case CAR: Result = "!car"; break;
+ case CDR: Result = "!cdr"; break;
+ case LNULL: Result = "!null"; break;
+ }
+ return Result + "(" + LHS->getAsString() + ")";
+}
+
+Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
+ 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()) {
+ bool LIsOps =
+ LOp->getDef()->getName() == "outs" ||
+ LOp->getDef()->getName() != "ins" ||
+ LOp->getDef()->getName() != "defs";
+ bool RIsOps =
+ ROp->getDef()->getName() == "outs" ||
+ ROp->getDef()->getName() != "ins" ||
+ ROp->getDef()->getName() != "defs";
+ if (!LIsOps || !RIsOps)
+ 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 NAMECONCAT: {
+ StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
+ StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
+ if (LHSs && RHSs) {
+ std::string Name(LHSs->getValue() + RHSs->getValue());
+
+ // From TGParser::ParseIDValue
+ if (CurRec) {
+ if (const RecordVal *RV = CurRec->getValue(Name)) {
+ if (RV->getType() != getType()) {
+ throw "type mismatch in nameconcat";
+ }
+ return new VarInit(Name, RV->getType());
+ }
+
+ std::string TemplateArgName = CurRec->getName()+":"+Name;
+ if (CurRec->isTemplateArg(TemplateArgName)) {
+ const RecordVal *RV = CurRec->getValue(TemplateArgName);
+ assert(RV && "Template arg doesn't exist??");
+
+ if (RV->getType() != getType()) {
+ throw "type mismatch in nameconcat";
+ }
+
+ return new VarInit(TemplateArgName, RV->getType());
+ }
+ }
+
+ if (CurMultiClass) {
+ std::string MCName = CurMultiClass->Rec.getName()+"::"+Name;
+ if (CurMultiClass->Rec.isTemplateArg(MCName)) {
+ const RecordVal *RV = CurMultiClass->Rec.getValue(MCName);
+ assert(RV && "Template arg doesn't exist??");
+
+ if (RV->getType() != getType()) {
+ throw "type mismatch in nameconcat";
+ }
+
+ return new VarInit(MCName, RV->getType());
+ }
+ }
+
+ if (Record *D = Records.getDef(Name))
+ return new DefInit(D);
+
+ cerr << "Variable not defined: '" + Name + "'\n";
+ assert(0 && "Variable not found");
+ return 0;
+ }
+ break;
+ }
+ case SHL:
+ case SRA:
+ case SRL: {
+ IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
+ IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
+ if (LHSi && RHSi) {
+ int64_t LHSv = LHSi->getValue(), RHSv = RHSi->getValue();
+ int64_t Result;
+ switch (getOpcode()) {
+ default: assert(0 && "Bad opcode!");
+ case SHL: Result = LHSv << RHSv; break;
+ case SRA: Result = LHSv >> RHSv; break;
+ case SRL: Result = (uint64_t)LHSv >> (uint64_t)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, getType()))->Fold(&R, 0);
+ return Fold(&R, 0);
+}
+
+std::string BinOpInit::getAsString() const {
+ std::string Result;
+ switch (Opc) {
+ case CONCAT: Result = "!con"; break;
+ case SHL: Result = "!shl"; break;
+ case SRA: Result = "!sra"; break;
+ case SRL: Result = "!srl"; break;
+ case STRCONCAT: Result = "!strconcat"; break;
+ case NAMECONCAT:
+ Result = "!nameconcat<" + getType()->getAsString() + ">"; break;
+ }
+ return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
+}
+
+static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
+ Record *CurRec, MultiClass *CurMultiClass);
+
+static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg,
+ RecTy *Type, Record *CurRec,
+ MultiClass *CurMultiClass) {
+ std::vector<Init *> NewOperands;
+
+ TypedInit *TArg = dynamic_cast<TypedInit*>(Arg);
+
+ // If this is a dag, recurse
+ if (TArg && TArg->getType()->getAsString() == "dag") {
+ Init *Result = ForeachHelper(LHS, Arg, RHSo, Type,
+ CurRec, CurMultiClass);
+ if (Result != 0) {
+ return Result;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ for (int i = 0; i < RHSo->getNumOperands(); ++i) {
+ OpInit *RHSoo = dynamic_cast<OpInit*>(RHSo->getOperand(i));
+
+ if (RHSoo) {
+ Init *Result = EvaluateOperation(RHSoo, LHS, Arg,
+ Type, CurRec, CurMultiClass);
+ if (Result != 0) {
+ NewOperands.push_back(Result);
+ }
+ else {
+ NewOperands.push_back(Arg);
+ }
+ }
+ else if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
+ NewOperands.push_back(Arg);
+ }
+ else {
+ NewOperands.push_back(RHSo->getOperand(i));
+ }
+ }
+
+ // Now run the operator and use its result as the new leaf
+ OpInit *NewOp = RHSo->clone(NewOperands);
+ Init *NewVal = NewOp->Fold(CurRec, CurMultiClass);
+ if (NewVal != NewOp) {
+ delete NewOp;
+ return NewVal;
+ }
+ return 0;
+}
+
+static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
+ Record *CurRec, MultiClass *CurMultiClass) {
+ DagInit *MHSd = dynamic_cast<DagInit*>(MHS);
+ ListInit *MHSl = dynamic_cast<ListInit*>(MHS);
+
+ DagRecTy *DagType = dynamic_cast<DagRecTy*>(Type);
+ ListRecTy *ListType = dynamic_cast<ListRecTy*>(Type);
+
+ OpInit *RHSo = dynamic_cast<OpInit*>(RHS);
+
+ if (!RHSo) {
+ cerr << "!foreach requires an operator\n";
+ assert(0 && "No operator for !foreach");
+ }
+
+ TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS);
+
+ if (!LHSt) {
+ cerr << "!foreach requires typed variable\n";
+ assert(0 && "No typed variable for !foreach");
+ }
+
+ if ((MHSd && DagType) || (MHSl && ListType)) {
+ if (MHSd) {
+ Init *Val = MHSd->getOperator();
+ Init *Result = EvaluateOperation(RHSo, LHS, Val,
+ Type, CurRec, CurMultiClass);
+ if (Result != 0) {
+ Val = Result;
+ }
+
+ std::vector<std::pair<Init *, std::string> > args;
+ for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) {
+ Init *Arg;
+ std::string ArgName;
+ Arg = MHSd->getArg(i);
+ ArgName = MHSd->getArgName(i);
+
+ // Process args
+ Init *Result = EvaluateOperation(RHSo, LHS, Arg, Type,
+ CurRec, CurMultiClass);
+ if (Result != 0) {
+ Arg = Result;
+ }
+
+ // TODO: Process arg names
+ args.push_back(std::make_pair(Arg, ArgName));
+ }
+
+ return new DagInit(Val, "", args);
+ }
+ if (MHSl) {
+ std::vector<Init *> NewOperands;
+ std::vector<Init *> NewList(MHSl->begin(), MHSl->end());
+
+ for (ListInit::iterator li = NewList.begin(),
+ liend = NewList.end();
+ li != liend;
+ ++li) {
+ Init *Item = *li;
+ NewOperands.clear();
+ for(int i = 0; i < RHSo->getNumOperands(); ++i) {
+ // First, replace the foreach variable with the list item
+ if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
+ NewOperands.push_back(Item);
+ }
+ else {
+ NewOperands.push_back(RHSo->getOperand(i));
+ }
+ }
+
+ // Now run the operator and use its result as the new list item
+ OpInit *NewOp = RHSo->clone(NewOperands);
+ Init *NewItem = NewOp->Fold(CurRec, CurMultiClass);
+ if (NewItem != NewOp) {
+ *li = NewItem;
+ delete NewOp;
+ }
+ }
+ return new ListInit(NewList);
+ }
+ }
+ return 0;
+}
+
+Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
+ switch (getOpcode()) {
+ default: assert(0 && "Unknown binop");
+ case SUBST: {
+ DefInit *LHSd = dynamic_cast<DefInit*>(LHS);
+ VarInit *LHSv = dynamic_cast<VarInit*>(LHS);
+ StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
+
+ DefInit *MHSd = dynamic_cast<DefInit*>(MHS);
+ VarInit *MHSv = dynamic_cast<VarInit*>(MHS);
+ StringInit *MHSs = dynamic_cast<StringInit*>(MHS);
+
+ DefInit *RHSd = dynamic_cast<DefInit*>(RHS);
+ VarInit *RHSv = dynamic_cast<VarInit*>(RHS);
+ StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
+
+ if ((LHSd && MHSd && RHSd)
+ || (LHSv && MHSv && RHSv)
+ || (LHSs && MHSs && RHSs)) {
+ if (RHSd) {
+ Record *Val = RHSd->getDef();
+ if (LHSd->getAsString() == RHSd->getAsString()) {
+ Val = MHSd->getDef();
+ }
+ return new DefInit(Val);
+ }
+ if (RHSv) {
+ std::string Val = RHSv->getName();
+ if (LHSv->getAsString() == RHSv->getAsString()) {
+ Val = MHSv->getName();
+ }
+ return new VarInit(Val, getType());
+ }
+ if (RHSs) {
+ std::string Val = RHSs->getValue();
+
+ std::string::size_type found;
+ do {
+ found = Val.find(LHSs->getValue());
+ if (found != std::string::npos) {
+ Val.replace(found, LHSs->getValue().size(), MHSs->getValue());
+ }
+ } while (found != std::string::npos);
+
+ return new StringInit(Val);
+ }
+ }
+ break;
+ }
+
+ case FOREACH: {
+ Init *Result = ForeachHelper(LHS, MHS, RHS, getType(),
+ CurRec, CurMultiClass);
+ if (Result != 0) {
+ return Result;
+ }
+ break;
+ }
+
+ case IF: {
+ IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
+ if (LHSi) {
+ if (LHSi->getValue()) {
+ return MHS;
+ }
+ else {
+ return RHS;
+ }
+ }
+ break;
+ }
+ }
+
+ return this;
+}
+
+Init *TernOpInit::resolveReferences(Record &R, const RecordVal *RV) {
+ Init *lhs = LHS->resolveReferences(R, RV);
+ Init *mhs = MHS->resolveReferences(R, RV);
+ Init *rhs = RHS->resolveReferences(R, RV);
+
+ if (LHS != lhs || MHS != mhs || RHS != rhs)
+ return (new TernOpInit(getOpcode(), lhs, mhs, rhs, getType()))->Fold(&R, 0);
+ return Fold(&R, 0);
+}
+
+std::string TernOpInit::getAsString() const {
+ std::string Result;
+ switch (Opc) {
+ case SUBST: Result = "!subst"; break;
+ case FOREACH: Result = "!foreach"; break;
+ case IF: Result = "!if"; break;
+ }
+ return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", "
+ + RHS->getAsString() + ")";
+}
+
+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());
+ if (!LI) {
+ VarInit *VI = dynamic_cast<VarInit*>(RV->getValue());
+ assert(VI && "Invalid list element!");
+ return new VarListElementInit(VI, Elt);
+ }
+
+ 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;
+}
+
+std::string VarBitInit::getAsString() const {
+ return TI->getAsString() + "{" + utostr(Bit) + "}";
+}
+
+Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) {
+ if (Init *I = getVariable()->resolveBitReference(R, RV, getBitNum()))
+ return I;
+ return this;
+}
+
+std::string VarListElementInit::getAsString() const {
+ return TI->getAsString() + "[" + utostr(Element) + "]";
+}
+
+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();
+}
+
+
+std::string DefInit::getAsString() const {
+ return 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) {
+ 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;
+}
+
+
+std::string DagInit::getAsString() const {
+ std::string Result = "(" + Val->getAsString();
+ if (!ValName.empty())
+ Result += ":" + ValName;
+ if (Args.size()) {
+ Result += " " + Args[0]->getAsString();
+ if (!ArgNames[0].empty()) Result += ":$" + ArgNames[0];
+ for (unsigned i = 1, e = Args.size(); i != e; ++i) {
+ Result += ", " + Args[i]->getAsString();
+ if (!ArgNames[i].empty()) Result += ":$" + ArgNames[i];
+ }
+ }
+ return Result + ")";
+}
+
+
+//===----------------------------------------------------------------------===//
+// 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 int64_t, throwing an exception if the field does not exist or if
+/// the value is not the right type.
+///
+int64_t 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!";
+}
+
+/// getValueAsListOfInts - This method looks up the specified field and returns
+/// its value as a vector of integers, throwing an exception if the field does
+/// not exist or if the value is not the right type.
+///
+std::vector<int64_t>
+Record::getValueAsListOfInts(const std::string &FieldName) const {
+ ListInit *List = getValueAsListInit(FieldName);
+ std::vector<int64_t> Ints;
+ for (unsigned i = 0; i < List->getSize(); i++) {
+ if (IntInit *II = dynamic_cast<IntInit*>(List->getElement(i))) {
+ Ints.push_back(II->getValue());
+ } else {
+ throw "Record `" + getName() + "', field `" + FieldName +
+ "' does not have a list of ints initializer!";
+ }
+ }
+ return Ints;
+}
+
+/// 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 MultiClass::dump() const {
+ cerr << "Record:\n";
+ Rec.dump();
+
+ cerr << "Defs:\n";
+ for (RecordVector::const_iterator r = DefPrototypes.begin(),
+ rend = DefPrototypes.end();
+ r != rend;
+ ++r) {
+ (*r)->dump();
+ }
+}
+
+
+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 000000000000..4284cabf8557
--- /dev/null
+++ b/utils/TableGen/Record.h
@@ -0,0 +1,1444 @@
+//===- Record.h - Classes to represent Table Records ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "TGSourceMgr.h"
+#include "llvm/Support/DataTypes.h"
+#include <map>
+#include <ostream>
+
+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 UnOpInit;
+class BinOpInit;
+class TernOpInit;
+class DefInit;
+class DagInit;
+class TypedInit;
+class VarInit;
+class FieldInit;
+class VarBitInit;
+class VarListElementInit;
+
+// Other classes.
+class Record;
+class RecordVal;
+struct MultiClass;
+
+//===----------------------------------------------------------------------===//
+// Type Classes
+//===----------------------------------------------------------------------===//
+
+struct RecTy {
+ virtual ~RecTy() {}
+
+ virtual std::string getAsString() const = 0;
+ void print(std::ostream &OS) const { OS << getAsString(); }
+ 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( UnOpInit *UI) {
+ return convertValue((TypedInit*)UI);
+ }
+ virtual Init *convertValue( BinOpInit *UI) {
+ return convertValue((TypedInit*)UI);
+ }
+ virtual Init *convertValue( TernOpInit *UI) {
+ return convertValue((TypedInit*)UI);
+ }
+ 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( UnOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ std::string getAsString() const { return "bit"; }
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+ virtual bool baseClassOf(const BitRecTy *RHS) const { return true; }
+ virtual bool baseClassOf(const BitsRecTy *RHS) const;
+ virtual bool baseClassOf(const IntRecTy *RHS) const { return true; }
+ virtual bool baseClassOf(const StringRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const ListRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const DagRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; }
+
+};
+
+
+// BitsRecTy - 'bits<n>' - Represent a fixed number of bits
+/// BitsRecTy - 'bits&lt;n&gt;' - Represent a fixed number of bits
+///
+class BitsRecTy : public RecTy {
+ unsigned Size;
+public:
+ explicit 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( UnOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ std::string getAsString() const;
+
+ 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( UnOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ std::string getAsString() const { return "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( UnOpInit *BO);
+ virtual Init *convertValue( BinOpInit *BO);
+ virtual Init *convertValue( TernOpInit *BO) { return RecTy::convertValue(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);}
+
+ std::string getAsString() const { return "string"; }
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+
+ virtual bool baseClassOf(const BitRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const IntRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const StringRecTy *RHS) const { return true; }
+ virtual bool baseClassOf(const ListRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const DagRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; }
+};
+
+// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must be of
+// the specified type.
+/// ListRecTy - 'list&lt;Ty&gt;' - Represent a list of values, all of which must
+/// be of the specified type.
+///
+class ListRecTy : public RecTy {
+ RecTy *Ty;
+public:
+ explicit 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( UnOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ std::string getAsString() 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( UnOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ std::string getAsString() const { return "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( UnOpInit *BO);
+ virtual Init *convertValue( BinOpInit *BO);
+ virtual Init *convertValue( TernOpInit *BO) { return RecTy::convertValue(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);}
+
+ std::string getAsString() const { return "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:
+ explicit 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( UnOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);}
+ virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);}
+ 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);}
+
+ std::string getAsString() 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.
+ void print(std::ostream &OS) const { OS << getAsString(); }
+
+ /// getAsString - Convert this value to a string form.
+ virtual std::string getAsString() 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;
+}
+
+/// TypedInit - This is the common super-class of types that have a specific,
+/// explicit, type.
+///
+class TypedInit : public Init {
+ RecTy *Ty;
+public:
+ explicit 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;
+};
+
+
+/// 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 std::string getAsString() const { return "?"; }
+};
+
+
+/// BitInit - true/false - Represent a concrete initializer for a bit.
+///
+class BitInit : public Init {
+ bool Value;
+public:
+ explicit BitInit(bool V) : Value(V) {}
+
+ bool getValue() const { return Value; }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ virtual std::string getAsString() const { return 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:
+ explicit 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 std::string getAsString() 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 {
+ int64_t Value;
+public:
+ explicit IntInit(int64_t V) : Value(V) {}
+
+ int64_t getValue() const { return Value; }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+ virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
+
+ virtual std::string getAsString() const;
+};
+
+
+/// StringInit - "foo" - Represent an initialization by a string value.
+///
+class StringInit : public TypedInit {
+ std::string Value;
+public:
+ explicit StringInit(const std::string &V)
+ : TypedInit(new StringRecTy), Value(V) {}
+
+ const std::string &getValue() const { return Value; }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ virtual std::string getAsString() const { return "\"" + Value + "\""; }
+
+ /// 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) {
+ assert(0 && "Illegal bit reference off string");
+ return 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) {
+ assert(0 && "Illegal element reference off string");
+ return 0;
+ }
+};
+
+/// CodeInit - "[{...}]" - Represent a code fragment.
+///
+class CodeInit : public Init {
+ std::string Value;
+public:
+ explicit CodeInit(const std::string &V) : Value(V) {}
+
+ const std::string getValue() const { return Value; }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ virtual std::string getAsString() const { return "[{" + Value + "}]"; }
+};
+
+/// ListInit - [AL, AH, CL] - Represent a list of defs
+///
+class ListInit : public Init {
+ std::vector<Init*> Values;
+public:
+ typedef std::vector<Init*>::iterator iterator;
+ typedef std::vector<Init*>::const_iterator const_iterator;
+
+ explicit ListInit(std::vector<Init*> &Vs) {
+ Values.swap(Vs);
+ }
+ explicit ListInit(iterator Start, iterator End)
+ : Values(Start, End) {}
+
+ 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 std::string getAsString() const;
+
+ inline iterator begin() { return Values.begin(); }
+ inline const_iterator begin() const { return Values.begin(); }
+ inline iterator end () { return Values.end(); }
+ inline const_iterator end () const { return Values.end(); }
+
+ inline size_t size () const { return Values.size(); }
+ inline bool empty() const { return Values.empty(); }
+};
+
+
+/// OpInit - Base class for operators
+///
+class OpInit : public TypedInit {
+public:
+ OpInit(RecTy *Type) : TypedInit(Type) {}
+
+ // Clone - Clone this operator, replacing arguments with the new list
+ virtual OpInit *clone(std::vector<Init *> &Operands) = 0;
+
+ virtual int getNumOperands(void) const = 0;
+ virtual Init *getOperand(int i) = 0;
+
+ // Fold - If possible, fold this to a simpler init. Return this if not
+ // possible to fold.
+ virtual Init *Fold(Record *CurRec, MultiClass *CurMultiClass) = 0;
+
+ 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);
+};
+
+
+/// UnOpInit - !op (X) - Transform an init.
+///
+class UnOpInit : public OpInit {
+public:
+ enum UnaryOp { CAST, CAR, CDR, LNULL };
+private:
+ UnaryOp Opc;
+ Init *LHS;
+public:
+ UnOpInit(UnaryOp opc, Init *lhs, RecTy *Type) :
+ OpInit(Type), Opc(opc), LHS(lhs) {
+ }
+
+ // Clone - Clone this operator, replacing arguments with the new list
+ virtual OpInit *clone(std::vector<Init *> &Operands) {
+ assert(Operands.size() == 1 &&
+ "Wrong number of operands for unary operation");
+ return new UnOpInit(getOpcode(), *Operands.begin(), getType());
+ }
+
+ int getNumOperands(void) const { return 1; }
+ Init *getOperand(int i) {
+ assert(i == 0 && "Invalid operand id for unary operator");
+ return getOperand();
+ }
+
+ UnaryOp getOpcode() const { return Opc; }
+ Init *getOperand() const { return LHS; }
+
+ // Fold - If possible, fold this to a simpler init. Return this if not
+ // possible to fold.
+ Init *Fold(Record *CurRec, MultiClass *CurMultiClass);
+
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+
+ virtual std::string getAsString() const;
+};
+
+/// BinOpInit - !op (X, Y) - Combine two inits.
+///
+class BinOpInit : public OpInit {
+public:
+ enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT, NAMECONCAT };
+private:
+ BinaryOp Opc;
+ Init *LHS, *RHS;
+public:
+ BinOpInit(BinaryOp opc, Init *lhs, Init *rhs, RecTy *Type) :
+ OpInit(Type), Opc(opc), LHS(lhs), RHS(rhs) {
+ }
+
+ // Clone - Clone this operator, replacing arguments with the new list
+ virtual OpInit *clone(std::vector<Init *> &Operands) {
+ assert(Operands.size() == 2 &&
+ "Wrong number of operands for binary operation");
+ return new BinOpInit(getOpcode(), Operands[0], Operands[1], getType());
+ }
+
+ int getNumOperands(void) const { return 2; }
+ Init *getOperand(int i) {
+ assert((i == 0 || i == 1) && "Invalid operand id for binary operator");
+ if (i == 0) {
+ return getLHS();
+ }
+ else {
+ return getRHS();
+ }
+ }
+
+ 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(Record *CurRec, MultiClass *CurMultiClass);
+
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+
+ virtual std::string getAsString() const;
+};
+
+/// TernOpInit - !op (X, Y, Z) - Combine two inits.
+///
+class TernOpInit : public OpInit {
+public:
+ enum TernaryOp { SUBST, FOREACH, IF };
+private:
+ TernaryOp Opc;
+ Init *LHS, *MHS, *RHS;
+public:
+ TernOpInit(TernaryOp opc, Init *lhs, Init *mhs, Init *rhs, RecTy *Type) :
+ OpInit(Type), Opc(opc), LHS(lhs), MHS(mhs), RHS(rhs) {
+ }
+
+ // Clone - Clone this operator, replacing arguments with the new list
+ virtual OpInit *clone(std::vector<Init *> &Operands) {
+ assert(Operands.size() == 3 &&
+ "Wrong number of operands for ternary operation");
+ return new TernOpInit(getOpcode(), Operands[0], Operands[1], Operands[2],
+ getType());
+ }
+
+ int getNumOperands(void) const { return 3; }
+ Init *getOperand(int i) {
+ assert((i == 0 || i == 1 || i == 2) &&
+ "Invalid operand id for ternary operator");
+ if (i == 0) {
+ return getLHS();
+ }
+ else if (i == 1) {
+ return getMHS();
+ }
+ else {
+ return getRHS();
+ }
+ }
+
+ TernaryOp getOpcode() const { return Opc; }
+ Init *getLHS() const { return LHS; }
+ Init *getMHS() const { return MHS; }
+ Init *getRHS() const { return RHS; }
+
+ // Fold - If possible, fold this to a simpler init. Return this if not
+ // possible to fold.
+ Init *Fold(Record *CurRec, MultiClass *CurMultiClass);
+
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+
+ virtual std::string getAsString() const;
+};
+
+
+/// VarInit - 'Opcode' - Represent a reference to an entire variable object.
+///
+class VarInit : public TypedInit {
+ std::string VarName;
+public:
+ explicit 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 std::string getAsString() const { return 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 std::string getAsString() const;
+ 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 std::string getAsString() const;
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+};
+
+/// DefInit - AL - Represent a reference to a 'def' in the description
+///
+class DefInit : public TypedInit {
+ Record *Def;
+public:
+ explicit DefInit(Record *D) : TypedInit(new RecordRecTy(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 std::string getAsString() const;
+
+ /// 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) {
+ assert(0 && "Illegal bit reference off def");
+ return 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) {
+ assert(0 && "Illegal element reference off def");
+ return 0;
+ }
+};
+
+
+/// 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 std::string getAsString() const {
+ return Rec->getAsString() + "." + 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 TypedInit {
+ Init *Val;
+ std::string ValName;
+ std::vector<Init*> Args;
+ std::vector<std::string> ArgNames;
+public:
+ DagInit(Init *V, std::string VN,
+ const std::vector<std::pair<Init*, std::string> > &args)
+ : TypedInit(new DagRecTy), Val(V), ValName(VN) {
+ 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, std::string VN, const std::vector<Init*> &args,
+ const std::vector<std::string> &argNames)
+ : TypedInit(new DagRecTy), Val(V), ValName(VN), Args(args), ArgNames(argNames) {
+ }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ Init *getOperator() const { return Val; }
+
+ const std::string &getName() const { return ValName; }
+
+ 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 std::string getAsString() const;
+
+ typedef std::vector<Init*>::iterator arg_iterator;
+ typedef std::vector<Init*>::const_iterator const_arg_iterator;
+ typedef std::vector<std::string>::iterator name_iterator;
+ typedef std::vector<std::string>::const_iterator const_name_iterator;
+
+ inline arg_iterator arg_begin() { return Args.begin(); }
+ inline const_arg_iterator arg_begin() const { return Args.begin(); }
+ inline arg_iterator arg_end () { return Args.end(); }
+ inline const_arg_iterator arg_end () const { return Args.end(); }
+
+ inline size_t arg_size () const { return Args.size(); }
+ inline bool arg_empty() const { return Args.empty(); }
+
+ inline name_iterator name_begin() { return ArgNames.begin(); }
+ inline const_name_iterator name_begin() const { return ArgNames.begin(); }
+ inline name_iterator name_end () { return ArgNames.end(); }
+ inline const_name_iterator name_end () const { return ArgNames.end(); }
+
+ inline size_t name_size () const { return ArgNames.size(); }
+ inline bool name_empty() const { return ArgNames.empty(); }
+
+ virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit) {
+ assert(0 && "Illegal bit reference off dag");
+ return 0;
+ }
+
+ virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
+ unsigned Elt) {
+ assert(0 && "Illegal element reference off dag");
+ return 0;
+ }
+
+};
+
+//===----------------------------------------------------------------------===//
+// 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;
+ TGLoc Loc;
+ std::vector<std::string> TemplateArgs;
+ std::vector<RecordVal> Values;
+ std::vector<Record*> SuperClasses;
+public:
+
+ explicit Record(const std::string &N, TGLoc loc) : Name(N), Loc(loc) {}
+ ~Record() {}
+
+ const std::string &getName() const { return Name; }
+ void setName(const std::string &Name); // Also updates RecordKeeper.
+
+ TGLoc getLoc() const { return Loc; }
+
+ 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(const 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
+ /// 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*> getValueAsListOfDefs(const std::string &FieldName) const;
+
+ /// getValueAsListOfInts - This method looks up the specified field and returns
+ /// its value as a vector of integers, throwing an exception if the field does
+ /// not exist or if the value is not the right type.
+ ///
+ std::vector<int64_t> getValueAsListOfInts(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 int64_t, throwing an exception if the field does not exist or
+ /// if the value is not the right type.
+ ///
+ int64_t 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);
+
+struct MultiClass {
+ Record Rec; // Placeholder for template args and Name.
+ typedef std::vector<Record*> RecordVector;
+ RecordVector DefPrototypes;
+
+ void dump() const;
+
+ MultiClass(const std::string &Name, TGLoc Loc) : Rec(Name, Loc) {}
+};
+
+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;
+};
+
+/// LessRecord - Sorting predicate to sort record pointers by name.
+///
+struct LessRecord {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getName() < Rec2->getName();
+ }
+};
+
+/// LessRecordFieldName - Sorting predicate to sort record pointers by their
+/// name field.
+///
+struct LessRecordFieldName {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getValueAsString("Name") < Rec2->getValueAsString("Name");
+ }
+};
+
+
+class TGError {
+ TGLoc Loc;
+ std::string Message;
+public:
+ TGError(TGLoc loc, const std::string &message) : Loc(loc), Message(message) {}
+
+ TGLoc getLoc() const { return Loc; }
+ const std::string &getMessage() const { return Message; }
+};
+
+
+std::ostream &operator<<(std::ostream &OS, const RecordKeeper &RK);
+
+extern RecordKeeper Records;
+
+void PrintError(TGLoc ErrorLoc, const std::string &Msg);
+
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
new file mode 100644
index 000000000000..dcf965cc1d79
--- /dev/null
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -0,0 +1,907 @@
+//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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>
+#include <algorithm>
+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/TargetRegisterInfo.h\"\n";
+ OS << "#include <string>\n\n";
+
+ OS << "namespace llvm {\n\n";
+
+ OS << "struct " << ClassName << " : public TargetRegisterInfo {\n"
+ << " explicit " << ClassName
+ << "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n"
+ << " virtual int getDwarfRegNumFull(unsigned RegNum, "
+ << "unsigned Flavour) const;\n"
+ << " virtual int getDwarfRegNum(unsigned RegNum, bool isEH) const = 0;\n"
+ << " virtual bool needsStackRealignment(const MachineFunction &) const\n"
+ << " { return false; }\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";
+ OS << " = " << (i+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*>, LessRecord> &SubRegs,
+ std::map<Record*, std::set<Record*>, LessRecord> &SuperRegs,
+ std::map<Record*, std::set<Record*>, LessRecord> &Aliases) {
+ if (R == S) {
+ cerr << "Error: recursive sub-register relationship between"
+ << " register " << 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);
+}
+
+static void addSubSuperReg(Record *R, Record *S,
+ std::map<Record*, std::set<Record*>, LessRecord> &SubRegs,
+ std::map<Record*, std::set<Record*>, LessRecord> &SuperRegs,
+ std::map<Record*, std::set<Record*>, LessRecord> &Aliases) {
+ if (R == S) {
+ cerr << "Error: recursive sub-register relationship between"
+ << " register " << getQualifiedName(R)
+ << " and its sub-registers?\n";
+ abort();
+ }
+
+ if (!SubRegs[R].insert(S).second)
+ return;
+ addSuperReg(S, R, SubRegs, SuperRegs, Aliases);
+ 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);
+}
+
+class RegisterSorter {
+private:
+ std::map<Record*, std::set<Record*>, LessRecord> &RegisterSubRegs;
+
+public:
+ RegisterSorter(std::map<Record*, std::set<Record*>, LessRecord> &RS)
+ : RegisterSubRegs(RS) {};
+
+ bool operator()(Record *RegA, Record *RegB) {
+ // B is sub-register of A.
+ return RegisterSubRegs.count(RegA) && RegisterSubRegs[RegA].count(RegB);
+ }
+};
+
+// 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 " << Name
+ << "[] = {\n ";
+ for (unsigned i = 0, e = RC.VTs.size(); i != e; ++i)
+ OS << getEnumName(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;
+ std::map<unsigned, std::set<unsigned> > SuperRegClassMap;
+ 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 Classes...\n"
+ << " static const TargetRegisterClass* const "
+ << Name << "SubRegClasses [] = {\n ";
+
+ bool Empty = true;
+
+ for (unsigned subrc = 0, subrcMax = RC.SubRegClasses.size();
+ subrc != subrcMax; ++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;
+
+ std::map<unsigned, std::set<unsigned> >::iterator SCMI =
+ SuperRegClassMap.find(rc2);
+ if (SCMI == SuperRegClassMap.end()) {
+ SuperRegClassMap.insert(std::make_pair(rc2,
+ std::set<unsigned>()));
+ SCMI = SuperRegClassMap.find(rc2);
+ }
+ SCMI->second.insert(rc);
+ 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 super-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
+ << " Super-register Classes...\n"
+ << " static const TargetRegisterClass* const "
+ << Name << "SuperRegClasses [] = {\n ";
+
+ bool Empty = true;
+ std::map<unsigned, std::set<unsigned> >::iterator I =
+ SuperRegClassMap.find(rc);
+ if (I != SuperRegClassMap.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";
+ }
+
+ // 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];
+
+ // RC2 is a sub-class of RC if it is a valid replacement for any
+ // instruction operand where an RC register is required. It must satisfy
+ // these conditions:
+ //
+ // 1. All RC2 registers are also in RC.
+ // 2. The RC2 spill size must not be smaller that the RC spill size.
+ // 3. RC2 spill alignment must be compatible with RC.
+ //
+ // Sub-classes are used to determine if a virtual register can be used
+ // as an instruction operand, or if it must be copied first.
+
+ if (rc == rc2 || RC2.Elements.size() > RC.Elements.size() ||
+ (RC.SpillAlignment && RC2.SpillAlignment % RC.SpillAlignment) ||
+ 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() << "\", "
+ << RC.getName() + "VTs" << ", "
+ << RC.getName() + "Subclasses" << ", "
+ << RC.getName() + "Superclasses" << ", "
+ << RC.getName() + "SubRegClasses" << ", "
+ << RC.getName() + "SuperRegClasses" << ", "
+ << RC.SpillSize/8 << ", "
+ << RC.SpillAlignment/8 << ", "
+ << RC.CopyCost << ", "
+ << 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*>, LessRecord> RegisterSubRegs;
+ std::map<Record*, std::set<Record*>, LessRecord> RegisterSuperRegs;
+ std::map<Record*, std::set<Record*>, LessRecord> RegisterAliases;
+ std::map<Record*, std::vector<std::pair<int, Record*> > > SubRegVectors;
+ typedef std::map<Record*, std::vector<int64_t>, LessRecord> DwarfRegNumsMapTy;
+ DwarfRegNumsMapTy DwarfRegNums;
+
+ 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";
+ addSubSuperReg(R, SubReg, RegisterSubRegs, RegisterSuperRegs,
+ RegisterAliases);
+ }
+ }
+
+ // Print the SubregHashTable, a simple quadratically probed
+ // hash table for determining if a register is a subregister
+ // of another register.
+ unsigned NumSubRegs = 0;
+ std::map<Record*, unsigned> RegNo;
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ RegNo[Regs[i].TheDef] = i;
+ NumSubRegs += RegisterSubRegs[Regs[i].TheDef].size();
+ }
+
+ unsigned SubregHashTableSize = 2 * NextPowerOf2(2 * NumSubRegs);
+ unsigned* SubregHashTable = new unsigned[2 * SubregHashTableSize];
+ std::fill(SubregHashTable, SubregHashTable + 2 * SubregHashTableSize, ~0U);
+
+ unsigned hashMisses = 0;
+
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record* R = Regs[i].TheDef;
+ for (std::set<Record*>::iterator I = RegisterSubRegs[R].begin(),
+ E = RegisterSubRegs[R].end(); I != E; ++I) {
+ Record* RJ = *I;
+ // We have to increase the indices of both registers by one when
+ // computing the hash because, in the generated code, there
+ // will be an extra empty slot at register 0.
+ size_t index = ((i+1) + (RegNo[RJ]+1) * 37) & (SubregHashTableSize-1);
+ unsigned ProbeAmt = 2;
+ while (SubregHashTable[index*2] != ~0U &&
+ SubregHashTable[index*2+1] != ~0U) {
+ index = (index + ProbeAmt) & (SubregHashTableSize-1);
+ ProbeAmt += 2;
+
+ hashMisses++;
+ }
+
+ SubregHashTable[index*2] = i;
+ SubregHashTable[index*2+1] = RegNo[RJ];
+ }
+ }
+
+ OS << "\n\n // Number of hash collisions: " << hashMisses << "\n";
+
+ if (SubregHashTableSize) {
+ std::string Namespace = Regs[0].TheDef->getValueAsString("Namespace");
+
+ OS << " const unsigned SubregHashTable[] = { ";
+ for (unsigned i = 0; i < SubregHashTableSize - 1; ++i) {
+ if (i != 0)
+ // Insert spaces for nice formatting.
+ OS << " ";
+
+ if (SubregHashTable[2*i] != ~0U) {
+ OS << getQualifiedName(Regs[SubregHashTable[2*i]].TheDef) << ", "
+ << getQualifiedName(Regs[SubregHashTable[2*i+1]].TheDef) << ", \n";
+ } else {
+ OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister, \n";
+ }
+ }
+
+ unsigned Idx = SubregHashTableSize*2-2;
+ if (SubregHashTable[Idx] != ~0U) {
+ OS << " "
+ << getQualifiedName(Regs[SubregHashTable[Idx]].TheDef) << ", "
+ << getQualifiedName(Regs[SubregHashTable[Idx+1]].TheDef) << " };\n";
+ } else {
+ OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister };\n";
+ }
+
+ OS << " const unsigned SubregHashTableSize = "
+ << SubregHashTableSize << ";\n";
+ } else {
+ OS << " const unsigned SubregHashTable[] = { ~0U, ~0U };\n"
+ << " const unsigned SubregHashTableSize = 1;\n";
+ }
+
+ delete [] SubregHashTable;
+
+
+ // Print the SuperregHashTable, a simple quadratically probed
+ // hash table for determining if a register is a super-register
+ // of another register.
+ unsigned NumSupRegs = 0;
+ RegNo.clear();
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ RegNo[Regs[i].TheDef] = i;
+ NumSupRegs += RegisterSuperRegs[Regs[i].TheDef].size();
+ }
+
+ unsigned SuperregHashTableSize = 2 * NextPowerOf2(2 * NumSupRegs);
+ unsigned* SuperregHashTable = new unsigned[2 * SuperregHashTableSize];
+ std::fill(SuperregHashTable, SuperregHashTable + 2 * SuperregHashTableSize, ~0U);
+
+ hashMisses = 0;
+
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record* R = Regs[i].TheDef;
+ for (std::set<Record*>::iterator I = RegisterSuperRegs[R].begin(),
+ E = RegisterSuperRegs[R].end(); I != E; ++I) {
+ Record* RJ = *I;
+ // We have to increase the indices of both registers by one when
+ // computing the hash because, in the generated code, there
+ // will be an extra empty slot at register 0.
+ size_t index = ((i+1) + (RegNo[RJ]+1) * 37) & (SuperregHashTableSize-1);
+ unsigned ProbeAmt = 2;
+ while (SuperregHashTable[index*2] != ~0U &&
+ SuperregHashTable[index*2+1] != ~0U) {
+ index = (index + ProbeAmt) & (SuperregHashTableSize-1);
+ ProbeAmt += 2;
+
+ hashMisses++;
+ }
+
+ SuperregHashTable[index*2] = i;
+ SuperregHashTable[index*2+1] = RegNo[RJ];
+ }
+ }
+
+ OS << "\n\n // Number of hash collisions: " << hashMisses << "\n";
+
+ if (SuperregHashTableSize) {
+ std::string Namespace = Regs[0].TheDef->getValueAsString("Namespace");
+
+ OS << " const unsigned SuperregHashTable[] = { ";
+ for (unsigned i = 0; i < SuperregHashTableSize - 1; ++i) {
+ if (i != 0)
+ // Insert spaces for nice formatting.
+ OS << " ";
+
+ if (SuperregHashTable[2*i] != ~0U) {
+ OS << getQualifiedName(Regs[SuperregHashTable[2*i]].TheDef) << ", "
+ << getQualifiedName(Regs[SuperregHashTable[2*i+1]].TheDef) << ", \n";
+ } else {
+ OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister, \n";
+ }
+ }
+
+ unsigned Idx = SuperregHashTableSize*2-2;
+ if (SuperregHashTable[Idx] != ~0U) {
+ OS << " "
+ << getQualifiedName(Regs[SuperregHashTable[Idx]].TheDef) << ", "
+ << getQualifiedName(Regs[SuperregHashTable[Idx+1]].TheDef) << " };\n";
+ } else {
+ OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister };\n";
+ }
+
+ OS << " const unsigned SuperregHashTableSize = "
+ << SuperregHashTableSize << ";\n";
+ } else {
+ OS << " const unsigned SuperregHashTable[] = { ~0U, ~0U };\n"
+ << " const unsigned SuperregHashTableSize = 1;\n";
+ }
+
+ delete [] SuperregHashTable;
+
+
+ // Print the AliasHashTable, a simple quadratically probed
+ // hash table for determining if a register aliases another register.
+ unsigned NumAliases = 0;
+ RegNo.clear();
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ RegNo[Regs[i].TheDef] = i;
+ NumAliases += RegisterAliases[Regs[i].TheDef].size();
+ }
+
+ unsigned AliasesHashTableSize = 2 * NextPowerOf2(2 * NumAliases);
+ unsigned* AliasesHashTable = new unsigned[2 * AliasesHashTableSize];
+ std::fill(AliasesHashTable, AliasesHashTable + 2 * AliasesHashTableSize, ~0U);
+
+ hashMisses = 0;
+
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record* R = Regs[i].TheDef;
+ for (std::set<Record*>::iterator I = RegisterAliases[R].begin(),
+ E = RegisterAliases[R].end(); I != E; ++I) {
+ Record* RJ = *I;
+ // We have to increase the indices of both registers by one when
+ // computing the hash because, in the generated code, there
+ // will be an extra empty slot at register 0.
+ size_t index = ((i+1) + (RegNo[RJ]+1) * 37) & (AliasesHashTableSize-1);
+ unsigned ProbeAmt = 2;
+ while (AliasesHashTable[index*2] != ~0U &&
+ AliasesHashTable[index*2+1] != ~0U) {
+ index = (index + ProbeAmt) & (AliasesHashTableSize-1);
+ ProbeAmt += 2;
+
+ hashMisses++;
+ }
+
+ AliasesHashTable[index*2] = i;
+ AliasesHashTable[index*2+1] = RegNo[RJ];
+ }
+ }
+
+ OS << "\n\n // Number of hash collisions: " << hashMisses << "\n";
+
+ if (AliasesHashTableSize) {
+ std::string Namespace = Regs[0].TheDef->getValueAsString("Namespace");
+
+ OS << " const unsigned AliasesHashTable[] = { ";
+ for (unsigned i = 0; i < AliasesHashTableSize - 1; ++i) {
+ if (i != 0)
+ // Insert spaces for nice formatting.
+ OS << " ";
+
+ if (AliasesHashTable[2*i] != ~0U) {
+ OS << getQualifiedName(Regs[AliasesHashTable[2*i]].TheDef) << ", "
+ << getQualifiedName(Regs[AliasesHashTable[2*i+1]].TheDef) << ", \n";
+ } else {
+ OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister, \n";
+ }
+ }
+
+ unsigned Idx = AliasesHashTableSize*2-2;
+ if (AliasesHashTable[Idx] != ~0U) {
+ OS << " "
+ << getQualifiedName(Regs[AliasesHashTable[Idx]].TheDef) << ", "
+ << getQualifiedName(Regs[AliasesHashTable[Idx+1]].TheDef) << " };\n";
+ } else {
+ OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister };\n";
+ }
+
+ OS << " const unsigned AliasesHashTableSize = "
+ << AliasesHashTableSize << ";\n";
+ } else {
+ OS << " const unsigned AliasesHashTable[] = { ~0U, ~0U };\n"
+ << " const unsigned AliasesHashTableSize = 1;\n";
+ }
+
+ delete [] AliasesHashTable;
+
+ 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*>, LessRecord >::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*>, LessRecord>::iterator
+ I = RegisterSubRegs.begin(), E = RegisterSubRegs.end(); I != E; ++I) {
+ OS << " const unsigned " << I->first->getName() << "_SubRegsSet[] = { ";
+ std::vector<Record*> SubRegsVector;
+ for (std::set<Record*>::iterator ASI = I->second.begin(),
+ E = I->second.end(); ASI != E; ++ASI)
+ SubRegsVector.push_back(*ASI);
+ RegisterSorter RS(RegisterSubRegs);
+ std::stable_sort(SubRegsVector.begin(), SubRegsVector.end(), RS);
+ for (unsigned i = 0, e = SubRegsVector.size(); i != e; ++i)
+ OS << getQualifiedName(SubRegsVector[i]) << ", ";
+ 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*>, LessRecord >::iterator
+ I = RegisterSuperRegs.begin(), E = RegisterSuperRegs.end(); I != E; ++I) {
+ OS << " const unsigned " << I->first->getName() << "_SuperRegsSet[] = { ";
+
+ std::vector<Record*> SuperRegsVector;
+ for (std::set<Record*>::iterator ASI = I->second.begin(),
+ E = I->second.end(); ASI != E; ++ASI)
+ SuperRegsVector.push_back(*ASI);
+ RegisterSorter RS(RegisterSubRegs);
+ std::stable_sort(SuperRegsVector.begin(), SuperRegsVector.end(), RS);
+ for (unsigned i = 0, e = SuperRegsVector.size(); i != e; ++i)
+ OS << getQualifiedName(SuperRegsVector[i]) << ", ";
+ OS << "0 };\n";
+ }
+
+ OS<<"\n const TargetRegisterDesc RegisterDescriptors[] = { // Descriptors\n";
+ OS << " { \"NOREG\",\t\"NOREG\",\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("AsmName").empty())
+ OS << Reg.TheDef->getValueAsString("AsmName");
+ else
+ OS << Reg.getName();
+ OS << "\",\t\"";
+ OS << Reg.getName() << "\",\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 (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:\n return 0;\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: return 0;\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 << " };\n" << " 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"
+ << " : TargetRegisterInfo(RegisterDescriptors, " << Registers.size()+1
+ << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n "
+ << " CallFrameSetupOpcode, CallFrameDestroyOpcode,\n"
+ << " SubregHashTable, SubregHashTableSize,\n"
+ << " SuperregHashTable, SuperregHashTableSize,\n"
+ << " AliasesHashTable, AliasesHashTableSize) {\n"
+ << "}\n\n";
+
+ // Collect all information about dwarf register numbers
+
+ // First, just pull all provided information to the map
+ unsigned maxLength = 0;
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ Record *Reg = Registers[i].TheDef;
+ std::vector<int64_t> RegNums = Reg->getValueAsListOfInts("DwarfNumbers");
+ maxLength = std::max((size_t)maxLength, RegNums.size());
+ if (DwarfRegNums.count(Reg))
+ cerr << "Warning: DWARF numbers for register " << getQualifiedName(Reg)
+ << "specified multiple times\n";
+ DwarfRegNums[Reg] = RegNums;
+ }
+
+ // Now we know maximal length of number list. Append -1's, where needed
+ for (DwarfRegNumsMapTy::iterator
+ I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I)
+ for (unsigned i = I->second.size(), e = maxLength; i != e; ++i)
+ I->second.push_back(-1);
+
+ // Emit information about the dwarf register numbers.
+ OS << "int " << ClassName << "::getDwarfRegNumFull(unsigned RegNum, "
+ << "unsigned Flavour) const {\n"
+ << " switch (Flavour) {\n"
+ << " default:\n"
+ << " assert(0 && \"Unknown DWARF flavour\");\n"
+ << " return -1;\n";
+
+ for (unsigned i = 0, e = maxLength; i != e; ++i) {
+ OS << " case " << i << ":\n"
+ << " switch (RegNum) {\n"
+ << " default:\n"
+ << " assert(0 && \"Invalid RegNum\");\n"
+ << " return -1;\n";
+
+ // Sort by name to get a stable order.
+
+
+ for (DwarfRegNumsMapTy::iterator
+ I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) {
+ int RegNo = I->second[i];
+ if (RegNo != -2)
+ OS << " case " << getQualifiedName(I->first) << ":\n"
+ << " return " << RegNo << ";\n";
+ else
+ OS << " case " << getQualifiedName(I->first) << ":\n"
+ << " assert(0 && \"Invalid register for this mode\");\n"
+ << " return -1;\n";
+ }
+ OS << " };\n";
+ }
+
+ OS << " };\n}\n\n";
+
+ OS << "} // End llvm namespace \n";
+}
diff --git a/utils/TableGen/RegisterInfoEmitter.h b/utils/TableGen/RegisterInfoEmitter.h
new file mode 100644
index 000000000000..b5493a9f4574
--- /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 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 000000000000..a28e8bc3a463
--- /dev/null
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -0,0 +1,513 @@
+//===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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;
+
+//
+// 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(), LessRecordFieldName());
+
+ // Begin feature table
+ OS << "// Sorted (by key) array of values for CPU features.\n"
+ << "static const 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", "description", featureEnum, 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 const llvm::InstrStage Stages[] = {\n"
+ " { 0, 0 }, // No itinerary\n";
+
+ unsigned StageCount = 1;
+ 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 = StageCount;
+ StageCount += NStages;
+ 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 const 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"
+ << "std::string 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");
+
+ if (Value=="true" || Value=="false")
+ OS << " if ((Bits & " << Instance << ") != 0) "
+ << Attribute << " = " << Value << ";\n";
+ else
+ OS << " if ((Bits & " << Instance << ") != 0 && " << Attribute <<
+ " < " << Value << ") " << Attribute << " = " << Value << ";\n";
+ }
+
+ if (HasItineraries) {
+ OS << "\n"
+ << " InstrItinerary *Itinerary = (InstrItinerary *)"
+ << "Features.getInfo(ProcItinKV, ProcItinKVSize);\n"
+ << " InstrItins = InstrItineraryData(Stages, Itinerary);\n";
+ }
+
+ OS << " return Features.getCPU();\n"
+ << "}\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 000000000000..4fcd8f8b0b24
--- /dev/null
+++ b/utils/TableGen/SubtargetEmitter.h
@@ -0,0 +1,62 @@
+//===- SubtargetEmitter.h - Generate subtarget enumerations -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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/TGLexer.cpp b/utils/TableGen/TGLexer.cpp
new file mode 100644
index 000000000000..758d499a8b5f
--- /dev/null
+++ b/utils/TableGen/TGLexer.cpp
@@ -0,0 +1,460 @@
+//===- TGLexer.cpp - Lexer for TableGen -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement the Lexer for TableGen.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TGLexer.h"
+#include "TGSourceMgr.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <ostream>
+#include "llvm/Config/config.h"
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+using namespace llvm;
+
+TGLexer::TGLexer(TGSourceMgr &SM) : SrcMgr(SM) {
+ CurBuffer = 0;
+ CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
+ CurPtr = CurBuf->getBufferStart();
+ TokStart = 0;
+}
+
+TGLoc TGLexer::getLoc() const {
+ return TGLoc::getFromPointer(TokStart);
+}
+
+
+/// ReturnError - Set the error to the specified string at the specified
+/// location. This is defined to always return tgtok::Error.
+tgtok::TokKind TGLexer::ReturnError(const char *Loc, const std::string &Msg) {
+ PrintError(Loc, Msg);
+ return tgtok::Error;
+}
+
+
+void TGLexer::PrintError(const char *Loc, const std::string &Msg) const {
+ SrcMgr.PrintError(TGLoc::getFromPointer(Loc), Msg);
+}
+
+void TGLexer::PrintError(TGLoc Loc, const std::string &Msg) const {
+ SrcMgr.PrintError(Loc, Msg);
+}
+
+
+int TGLexer::getNextChar() {
+ char CurChar = *CurPtr++;
+ switch (CurChar) {
+ default:
+ return (unsigned char)CurChar;
+ case 0: {
+ // A nul character in the stream is either the end of the current buffer or
+ // a random nul in the file. Disambiguate that here.
+ if (CurPtr-1 != CurBuf->getBufferEnd())
+ return 0; // Just whitespace.
+
+ // If this is the end of an included file, pop the parent file off the
+ // include stack.
+ TGLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
+ if (ParentIncludeLoc != TGLoc()) {
+ CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
+ CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
+ CurPtr = ParentIncludeLoc.getPointer();
+ return getNextChar();
+ }
+
+ // Otherwise, return end of file.
+ --CurPtr; // Another call to lex will return EOF again.
+ return EOF;
+ }
+ case '\n':
+ case '\r':
+ // Handle the newline character by ignoring it and incrementing the line
+ // count. However, be careful about 'dos style' files with \n\r in them.
+ // Only treat a \n\r or \r\n as a single line.
+ if ((*CurPtr == '\n' || (*CurPtr == '\r')) &&
+ *CurPtr != CurChar)
+ ++CurPtr; // Eat the two char newline sequence.
+ return '\n';
+ }
+}
+
+tgtok::TokKind TGLexer::LexToken() {
+ TokStart = CurPtr;
+ // This always consumes at least one character.
+ int CurChar = getNextChar();
+
+ switch (CurChar) {
+ default:
+ // Handle letters: [a-zA-Z_]
+ if (isalpha(CurChar) || CurChar == '_' || CurChar == '#')
+ return LexIdentifier();
+
+ // Unknown character, emit an error.
+ return ReturnError(TokStart, "Unexpected character");
+ case EOF: return tgtok::Eof;
+ case ':': return tgtok::colon;
+ case ';': return tgtok::semi;
+ case '.': return tgtok::period;
+ case ',': return tgtok::comma;
+ case '<': return tgtok::less;
+ case '>': return tgtok::greater;
+ case ']': return tgtok::r_square;
+ case '{': return tgtok::l_brace;
+ case '}': return tgtok::r_brace;
+ case '(': return tgtok::l_paren;
+ case ')': return tgtok::r_paren;
+ case '=': return tgtok::equal;
+ case '?': return tgtok::question;
+
+ case 0:
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ // Ignore whitespace.
+ return LexToken();
+ case '/':
+ // If this is the start of a // comment, skip until the end of the line or
+ // the end of the buffer.
+ if (*CurPtr == '/')
+ SkipBCPLComment();
+ else if (*CurPtr == '*') {
+ if (SkipCComment())
+ return tgtok::Error;
+ } else // Otherwise, this is an error.
+ return ReturnError(TokStart, "Unexpected character");
+ return LexToken();
+ case '-': case '+':
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ return LexNumber();
+ case '"': return LexString();
+ case '$': return LexVarName();
+ case '[': return LexBracket();
+ case '!': return LexExclaim();
+ }
+}
+
+/// LexString - Lex "[^"]*"
+tgtok::TokKind TGLexer::LexString() {
+ const char *StrStart = CurPtr;
+
+ CurStrVal = "";
+
+ while (*CurPtr != '"') {
+ // If we hit the end of the buffer, report an error.
+ if (*CurPtr == 0 && CurPtr == CurBuf->getBufferEnd())
+ return ReturnError(StrStart, "End of file in string literal");
+
+ if (*CurPtr == '\n' || *CurPtr == '\r')
+ return ReturnError(StrStart, "End of line in string literal");
+
+ if (*CurPtr != '\\') {
+ CurStrVal += *CurPtr++;
+ continue;
+ }
+
+ ++CurPtr;
+
+ switch (*CurPtr) {
+ case '\\': case '\'': case '"':
+ // These turn into their literal character.
+ CurStrVal += *CurPtr++;
+ break;
+ case 't':
+ CurStrVal += '\t';
+ ++CurPtr;
+ break;
+ case 'n':
+ CurStrVal += '\n';
+ ++CurPtr;
+ break;
+
+ case '\n':
+ case '\r':
+ return ReturnError(CurPtr, "escaped newlines not supported in tblgen");
+
+ // If we hit the end of the buffer, report an error.
+ case '\0':
+ if (CurPtr == CurBuf->getBufferEnd())
+ return ReturnError(StrStart, "End of file in string literal");
+ // FALL THROUGH
+ default:
+ return ReturnError(CurPtr, "invalid escape in string literal");
+ }
+ }
+
+ ++CurPtr;
+ return tgtok::StrVal;
+}
+
+tgtok::TokKind TGLexer::LexVarName() {
+ if (!isalpha(CurPtr[0]) && CurPtr[0] != '_')
+ return ReturnError(TokStart, "Invalid variable name");
+
+ // Otherwise, we're ok, consume the rest of the characters.
+ const char *VarNameStart = CurPtr++;
+
+ while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_')
+ ++CurPtr;
+
+ CurStrVal.assign(VarNameStart, CurPtr);
+ return tgtok::VarName;
+}
+
+
+tgtok::TokKind TGLexer::LexIdentifier() {
+ // The first letter is [a-zA-Z_].
+ const char *IdentStart = TokStart;
+
+ // Match the rest of the identifier regex: [0-9a-zA-Z_]*
+ while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_'
+ || *CurPtr == '#') {
+ // If this contains a '#', make sure it's value
+ if (*CurPtr == '#') {
+ if (strncmp(CurPtr, "#NAME#", 6) != 0) {
+ return tgtok::Error;
+ }
+ CurPtr += 6;
+ }
+ else {
+ ++CurPtr;
+ }
+ }
+
+
+ // Check to see if this identifier is a keyword.
+ unsigned Len = CurPtr-IdentStart;
+
+ if (Len == 3 && !memcmp(IdentStart, "int", 3)) return tgtok::Int;
+ if (Len == 3 && !memcmp(IdentStart, "bit", 3)) return tgtok::Bit;
+ if (Len == 4 && !memcmp(IdentStart, "bits", 4)) return tgtok::Bits;
+ if (Len == 6 && !memcmp(IdentStart, "string", 6)) return tgtok::String;
+ if (Len == 4 && !memcmp(IdentStart, "list", 4)) return tgtok::List;
+ if (Len == 4 && !memcmp(IdentStart, "code", 4)) return tgtok::Code;
+ if (Len == 3 && !memcmp(IdentStart, "dag", 3)) return tgtok::Dag;
+
+ if (Len == 5 && !memcmp(IdentStart, "class", 5)) return tgtok::Class;
+ if (Len == 3 && !memcmp(IdentStart, "def", 3)) return tgtok::Def;
+ if (Len == 4 && !memcmp(IdentStart, "defm", 4)) return tgtok::Defm;
+ if (Len == 10 && !memcmp(IdentStart, "multiclass", 10))
+ return tgtok::MultiClass;
+ if (Len == 5 && !memcmp(IdentStart, "field", 5)) return tgtok::Field;
+ if (Len == 3 && !memcmp(IdentStart, "let", 3)) return tgtok::Let;
+ if (Len == 2 && !memcmp(IdentStart, "in", 2)) return tgtok::In;
+
+ if (Len == 7 && !memcmp(IdentStart, "include", 7)) {
+ if (LexInclude()) return tgtok::Error;
+ return Lex();
+ }
+
+ CurStrVal.assign(IdentStart, CurPtr);
+ return tgtok::Id;
+}
+
+/// LexInclude - We just read the "include" token. Get the string token that
+/// comes next and enter the include.
+bool TGLexer::LexInclude() {
+ // The token after the include must be a string.
+ tgtok::TokKind Tok = LexToken();
+ if (Tok == tgtok::Error) return true;
+ if (Tok != tgtok::StrVal) {
+ PrintError(getLoc(), "Expected filename after include");
+ return true;
+ }
+
+ // Get the string.
+ std::string Filename = CurStrVal;
+
+ // Try to find the file.
+ MemoryBuffer *NewBuf = MemoryBuffer::getFile(Filename.c_str());
+
+ // If the file didn't exist directly, see if it's in an include path.
+ for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) {
+ std::string IncFile = IncludeDirectories[i] + "/" + Filename;
+ NewBuf = MemoryBuffer::getFile(IncFile.c_str());
+ }
+
+ if (NewBuf == 0) {
+ PrintError(getLoc(), "Could not find include file '" + Filename + "'");
+ return true;
+ }
+
+ // Save the line number and lex buffer of the includer.
+ CurBuffer = SrcMgr.AddNewSourceBuffer(NewBuf, TGLoc::getFromPointer(CurPtr));
+
+ CurBuf = NewBuf;
+ CurPtr = CurBuf->getBufferStart();
+ return false;
+}
+
+void TGLexer::SkipBCPLComment() {
+ ++CurPtr; // skip the second slash.
+ while (1) {
+ switch (*CurPtr) {
+ case '\n':
+ case '\r':
+ return; // Newline is end of comment.
+ case 0:
+ // If this is the end of the buffer, end the comment.
+ if (CurPtr == CurBuf->getBufferEnd())
+ return;
+ break;
+ }
+ // Otherwise, skip the character.
+ ++CurPtr;
+ }
+}
+
+/// SkipCComment - This skips C-style /**/ comments. The only difference from C
+/// is that we allow nesting.
+bool TGLexer::SkipCComment() {
+ ++CurPtr; // skip the star.
+ unsigned CommentDepth = 1;
+
+ while (1) {
+ int CurChar = getNextChar();
+ switch (CurChar) {
+ case EOF:
+ PrintError(TokStart, "Unterminated comment!");
+ return true;
+ case '*':
+ // End of the comment?
+ if (CurPtr[0] != '/') break;
+
+ ++CurPtr; // End the */.
+ if (--CommentDepth == 0)
+ return false;
+ break;
+ case '/':
+ // Start of a nested comment?
+ if (CurPtr[0] != '*') break;
+ ++CurPtr;
+ ++CommentDepth;
+ break;
+ }
+ }
+}
+
+/// LexNumber - Lex:
+/// [-+]?[0-9]+
+/// 0x[0-9a-fA-F]+
+/// 0b[01]+
+tgtok::TokKind TGLexer::LexNumber() {
+ if (CurPtr[-1] == '0') {
+ if (CurPtr[0] == 'x') {
+ ++CurPtr;
+ const char *NumStart = CurPtr;
+ while (isxdigit(CurPtr[0]))
+ ++CurPtr;
+
+ // Requires at least one hex digit.
+ if (CurPtr == NumStart)
+ return ReturnError(CurPtr-2, "Invalid hexadecimal number");
+
+ errno = 0;
+ CurIntVal = strtoll(NumStart, 0, 16);
+ if (errno == EINVAL)
+ return ReturnError(CurPtr-2, "Invalid hexadecimal number");
+ if (errno == ERANGE) {
+ errno = 0;
+ CurIntVal = (int64_t)strtoull(NumStart, 0, 16);
+ if (errno == EINVAL)
+ return ReturnError(CurPtr-2, "Invalid hexadecimal number");
+ if (errno == ERANGE)
+ return ReturnError(CurPtr-2, "Hexadecimal number out of range");
+ }
+ return tgtok::IntVal;
+ } else if (CurPtr[0] == 'b') {
+ ++CurPtr;
+ const char *NumStart = CurPtr;
+ while (CurPtr[0] == '0' || CurPtr[0] == '1')
+ ++CurPtr;
+
+ // Requires at least one binary digit.
+ if (CurPtr == NumStart)
+ return ReturnError(CurPtr-2, "Invalid binary number");
+ CurIntVal = strtoll(NumStart, 0, 2);
+ return tgtok::IntVal;
+ }
+ }
+
+ // Check for a sign without a digit.
+ if (!isdigit(CurPtr[0])) {
+ if (CurPtr[-1] == '-')
+ return tgtok::minus;
+ else if (CurPtr[-1] == '+')
+ return tgtok::plus;
+ }
+
+ while (isdigit(CurPtr[0]))
+ ++CurPtr;
+ CurIntVal = strtoll(TokStart, 0, 10);
+ return tgtok::IntVal;
+}
+
+/// LexBracket - We just read '['. If this is a code block, return it,
+/// otherwise return the bracket. Match: '[' and '[{ ( [^}]+ | }[^]] )* }]'
+tgtok::TokKind TGLexer::LexBracket() {
+ if (CurPtr[0] != '{')
+ return tgtok::l_square;
+ ++CurPtr;
+ const char *CodeStart = CurPtr;
+ while (1) {
+ int Char = getNextChar();
+ if (Char == EOF) break;
+
+ if (Char != '}') continue;
+
+ Char = getNextChar();
+ if (Char == EOF) break;
+ if (Char == ']') {
+ CurStrVal.assign(CodeStart, CurPtr-2);
+ return tgtok::CodeFragment;
+ }
+ }
+
+ return ReturnError(CodeStart-2, "Unterminated Code Block");
+}
+
+/// LexExclaim - Lex '!' and '![a-zA-Z]+'.
+tgtok::TokKind TGLexer::LexExclaim() {
+ if (!isalpha(*CurPtr))
+ return ReturnError(CurPtr-1, "Invalid \"!operator\"");
+
+ const char *Start = CurPtr++;
+ while (isalpha(*CurPtr))
+ ++CurPtr;
+
+ // Check to see which operator this is.
+ unsigned Len = CurPtr-Start;
+
+ if (Len == 3 && !memcmp(Start, "con", 3)) return tgtok::XConcat;
+ if (Len == 3 && !memcmp(Start, "sra", 3)) return tgtok::XSRA;
+ if (Len == 3 && !memcmp(Start, "srl", 3)) return tgtok::XSRL;
+ if (Len == 3 && !memcmp(Start, "shl", 3)) return tgtok::XSHL;
+ if (Len == 9 && !memcmp(Start, "strconcat", 9)) return tgtok::XStrConcat;
+ if (Len == 10 && !memcmp(Start, "nameconcat", 10)) return tgtok::XNameConcat;
+ if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst;
+ if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach;
+ if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast;
+ if (Len == 3 && !memcmp(Start, "car", 3)) return tgtok::XCar;
+ if (Len == 3 && !memcmp(Start, "cdr", 3)) return tgtok::XCdr;
+ if (Len == 4 && !memcmp(Start, "null", 4)) return tgtok::XNull;
+ if (Len == 2 && !memcmp(Start, "if", 2)) return tgtok::XIf;
+
+ return ReturnError(Start-1, "Unknown operator");
+}
+
diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h
new file mode 100644
index 000000000000..ac3b9840039b
--- /dev/null
+++ b/utils/TableGen/TGLexer.h
@@ -0,0 +1,129 @@
+//===- TGLexer.h - Lexer for TableGen Files ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class represents the Lexer for tablegen files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TGLEXER_H
+#define TGLEXER_H
+
+#include "llvm/Support/DataTypes.h"
+#include <vector>
+#include <string>
+#include <iosfwd>
+#include <cassert>
+
+namespace llvm {
+class MemoryBuffer;
+class TGSourceMgr;
+class TGLoc;
+
+namespace tgtok {
+ enum TokKind {
+ // Markers
+ Eof, Error,
+
+ // Tokens with no info.
+ minus, plus, // - +
+ l_square, r_square, // [ ]
+ l_brace, r_brace, // { }
+ l_paren, r_paren, // ( )
+ less, greater, // < >
+ colon, semi, // ; :
+ comma, period, // , .
+ equal, question, // = ?
+
+ // Keywords.
+ Bit, Bits, Class, Code, Dag, Def, Defm, Field, In, Int, Let, List,
+ MultiClass, String,
+
+ // !keywords.
+ XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst,
+ XForEach, XCar, XCdr, XNull, XIf,
+
+ // Integer value.
+ IntVal,
+
+ // String valued tokens.
+ Id, StrVal, VarName, CodeFragment
+ };
+}
+
+/// TGLexer - TableGen Lexer class.
+class TGLexer {
+ TGSourceMgr &SrcMgr;
+
+ const char *CurPtr;
+ const MemoryBuffer *CurBuf;
+
+ // Information about the current token.
+ const char *TokStart;
+ tgtok::TokKind CurCode;
+ std::string CurStrVal; // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT
+ int64_t CurIntVal; // This is valid for INTVAL.
+
+ /// CurBuffer - This is the current buffer index we're lexing from as managed
+ /// by the SourceMgr object.
+ int CurBuffer;
+
+ // IncludeDirectories - This is the list of directories we should search for
+ // include files in.
+ std::vector<std::string> IncludeDirectories;
+public:
+ TGLexer(TGSourceMgr &SrcMgr);
+ ~TGLexer() {}
+
+ void setIncludeDirs(const std::vector<std::string> &Dirs) {
+ IncludeDirectories = Dirs;
+ }
+
+ tgtok::TokKind Lex() {
+ return CurCode = LexToken();
+ }
+
+ tgtok::TokKind getCode() const { return CurCode; }
+
+ const std::string &getCurStrVal() const {
+ assert((CurCode == tgtok::Id || CurCode == tgtok::StrVal ||
+ CurCode == tgtok::VarName || CurCode == tgtok::CodeFragment) &&
+ "This token doesn't have a string value");
+ return CurStrVal;
+ }
+ int64_t getCurIntVal() const {
+ assert(CurCode == tgtok::IntVal && "This token isn't an integer");
+ return CurIntVal;
+ }
+
+ TGLoc getLoc() const;
+
+ void PrintError(const char *Loc, const std::string &Msg) const;
+ void PrintError(TGLoc Loc, const std::string &Msg) const;
+
+private:
+ /// LexToken - Read the next token and return its code.
+ tgtok::TokKind LexToken();
+
+ tgtok::TokKind ReturnError(const char *Loc, const std::string &Msg);
+
+ int getNextChar();
+ void SkipBCPLComment();
+ bool SkipCComment();
+ tgtok::TokKind LexIdentifier();
+ bool LexInclude();
+ tgtok::TokKind LexString();
+ tgtok::TokKind LexVarName();
+ tgtok::TokKind LexNumber();
+ tgtok::TokKind LexBracket();
+ tgtok::TokKind LexExclaim();
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp
new file mode 100644
index 000000000000..fc6f29fd9f1b
--- /dev/null
+++ b/utils/TableGen/TGParser.cpp
@@ -0,0 +1,1937 @@
+//===- TGParser.cpp - Parser for TableGen Files ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement the Parser for TableGen.
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+
+#include "TGParser.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Streams.h"
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Support Code for the Semantic Actions.
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+struct SubClassReference {
+ TGLoc RefLoc;
+ Record *Rec;
+ std::vector<Init*> TemplateArgs;
+ SubClassReference() : Rec(0) {}
+
+ bool isInvalid() const { return Rec == 0; }
+};
+
+struct SubMultiClassReference {
+ TGLoc RefLoc;
+ MultiClass *MC;
+ std::vector<Init*> TemplateArgs;
+ SubMultiClassReference() : MC(0) {}
+
+ bool isInvalid() const { return MC == 0; }
+ void dump() const;
+};
+
+void SubMultiClassReference::dump() const {
+ cerr << "Multiclass:\n";
+
+ MC->dump();
+
+ cerr << "Template args:\n";
+ for (std::vector<Init *>::const_iterator i = TemplateArgs.begin(),
+ iend = TemplateArgs.end();
+ i != iend;
+ ++i) {
+ (*i)->dump();
+ }
+}
+
+} // end namespace llvm
+
+bool TGParser::AddValue(Record *CurRec, TGLoc Loc, const RecordVal &RV) {
+ if (CurRec == 0)
+ CurRec = &CurMultiClass->Rec;
+
+ if (RecordVal *ERV = CurRec->getValue(RV.getName())) {
+ // The value already exists in the class, treat this as a set.
+ if (ERV->setValue(RV.getValue()))
+ return Error(Loc, "New definition of '" + RV.getName() + "' of type '" +
+ RV.getType()->getAsString() + "' is incompatible with " +
+ "previous definition of type '" +
+ ERV->getType()->getAsString() + "'");
+ } else {
+ CurRec->addValue(RV);
+ }
+ return false;
+}
+
+/// SetValue -
+/// Return true on error, false on success.
+bool TGParser::SetValue(Record *CurRec, TGLoc Loc, const std::string &ValName,
+ const std::vector<unsigned> &BitList, Init *V) {
+ if (!V) return false;
+
+ if (CurRec == 0) CurRec = &CurMultiClass->Rec;
+
+ RecordVal *RV = CurRec->getValue(ValName);
+ if (RV == 0)
+ return Error(Loc, "Value '" + ValName + "' unknown!");
+
+ // Do not allow assignments like 'X = X'. This will just cause infinite loops
+ // in the resolution machinery.
+ if (BitList.empty())
+ if (VarInit *VI = dynamic_cast<VarInit*>(V))
+ if (VI->getName() == ValName)
+ return false;
+
+ // 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.empty()) {
+ BitsInit *CurVal = dynamic_cast<BitsInit*>(RV->getValue());
+ if (CurVal == 0)
+ return Error(Loc, "Value '" + ValName + "' is not a bits type");
+
+ // 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()));
+ return Error(Loc, "Initializer is not compatible with bit range");
+ }
+
+ // We should have a BitsInit type now.
+ BitsInit *BInit = dynamic_cast<BitsInit*>(BI);
+ assert(BInit != 0);
+
+ 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))
+ return Error(Loc, "Cannot set bit #" + utostr(Bit) + " of value '" +
+ ValName + "' more than once");
+ 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))
+ return Error(Loc, "Value '" + ValName + "' of type '" +
+ RV->getType()->getAsString() +
+ "' is incompatible with initializer '" + V->getAsString() +"'");
+ return false;
+}
+
+/// AddSubClass - Add SubClass as a subclass to CurRec, resolving its template
+/// args as SubClass's template arguments.
+bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
+ Record *SC = SubClass.Rec;
+ // 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)
+ if (AddValue(CurRec, SubClass.RefLoc, Vals[i]))
+ return true;
+
+ const std::vector<std::string> &TArgs = SC->getTemplateArgs();
+
+ // Ensure that an appropriate number of template arguments are specified.
+ if (TArgs.size() < SubClass.TemplateArgs.size())
+ return Error(SubClass.RefLoc, "More template args specified than expected");
+
+ // 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 < SubClass.TemplateArgs.size()) {
+ // If a value is specified for this template arg, set it now.
+ if (SetValue(CurRec, SubClass.RefLoc, TArgs[i], std::vector<unsigned>(),
+ SubClass.TemplateArgs[i]))
+ return true;
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[i]);
+
+ } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
+ return Error(SubClass.RefLoc,"Value not specified for template argument #"
+ + utostr(i) + " (" + TArgs[i] + ") of subclass '" +
+ SC->getName() + "'!");
+ }
+ }
+
+ // 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) {
+ if (CurRec->isSubClassOf(SCs[i]))
+ return Error(SubClass.RefLoc,
+ "Already subclass of '" + SCs[i]->getName() + "'!\n");
+ CurRec->addSuperClass(SCs[i]);
+ }
+
+ if (CurRec->isSubClassOf(SC))
+ return Error(SubClass.RefLoc,
+ "Already subclass of '" + SC->getName() + "'!\n");
+ CurRec->addSuperClass(SC);
+ return false;
+}
+
+/// AddSubMultiClass - Add SubMultiClass as a subclass to
+/// CurMC, resolving its template args as SubMultiClass's
+/// template arguments.
+bool TGParser::AddSubMultiClass(MultiClass *CurMC,
+ SubMultiClassReference &SubMultiClass) {
+ MultiClass *SMC = SubMultiClass.MC;
+ Record *CurRec = &CurMC->Rec;
+
+ const std::vector<RecordVal> &MCVals = CurRec->getValues();
+
+ // Add all of the values in the subclass into the current class.
+ const std::vector<RecordVal> &SMCVals = SMC->Rec.getValues();
+ for (unsigned i = 0, e = SMCVals.size(); i != e; ++i)
+ if (AddValue(CurRec, SubMultiClass.RefLoc, SMCVals[i]))
+ return true;
+
+ int newDefStart = CurMC->DefPrototypes.size();
+
+ // Add all of the defs in the subclass into the current multiclass.
+ for (MultiClass::RecordVector::const_iterator i = SMC->DefPrototypes.begin(),
+ iend = SMC->DefPrototypes.end();
+ i != iend;
+ ++i) {
+ // Clone the def and add it to the current multiclass
+ Record *NewDef = new Record(**i);
+
+ // Add all of the values in the superclass into the current def.
+ for (unsigned i = 0, e = MCVals.size(); i != e; ++i)
+ if (AddValue(NewDef, SubMultiClass.RefLoc, MCVals[i]))
+ return true;
+
+ CurMC->DefPrototypes.push_back(NewDef);
+ }
+
+ const std::vector<std::string> &SMCTArgs = SMC->Rec.getTemplateArgs();
+
+ // Ensure that an appropriate number of template arguments are
+ // specified.
+ if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size())
+ return Error(SubMultiClass.RefLoc,
+ "More template args specified than expected");
+
+ // 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 = SMCTArgs.size(); i != e; ++i) {
+ if (i < SubMultiClass.TemplateArgs.size()) {
+ // If a value is specified for this template arg, set it in the
+ // superclass now.
+ if (SetValue(CurRec, SubMultiClass.RefLoc, SMCTArgs[i],
+ std::vector<unsigned>(),
+ SubMultiClass.TemplateArgs[i]))
+ return true;
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(SMCTArgs[i]));
+
+ // Now remove it.
+ CurRec->removeValue(SMCTArgs[i]);
+
+ // If a value is specified for this template arg, set it in the
+ // new defs now.
+ for (MultiClass::RecordVector::iterator j =
+ CurMC->DefPrototypes.begin() + newDefStart,
+ jend = CurMC->DefPrototypes.end();
+ j != jend;
+ ++j) {
+ Record *Def = *j;
+
+ if (SetValue(Def, SubMultiClass.RefLoc, SMCTArgs[i],
+ std::vector<unsigned>(),
+ SubMultiClass.TemplateArgs[i]))
+ return true;
+
+ // Resolve it next.
+ Def->resolveReferencesTo(Def->getValue(SMCTArgs[i]));
+
+ // Now remove it
+ Def->removeValue(SMCTArgs[i]);
+ }
+ } else if (!CurRec->getValue(SMCTArgs[i])->getValue()->isComplete()) {
+ return Error(SubMultiClass.RefLoc,
+ "Value not specified for template argument #"
+ + utostr(i) + " (" + SMCTArgs[i] + ") of subclass '" +
+ SMC->Rec.getName() + "'!");
+ }
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Parser Code
+//===----------------------------------------------------------------------===//
+
+/// isObjectStart - Return true if this is a valid first token for an Object.
+static bool isObjectStart(tgtok::TokKind K) {
+ return K == tgtok::Class || K == tgtok::Def ||
+ K == tgtok::Defm || K == tgtok::Let || K == tgtok::MultiClass;
+}
+
+/// ParseObjectName - If an object name is specified, return it. Otherwise,
+/// return an anonymous name.
+/// ObjectName ::= ID
+/// ObjectName ::= /*empty*/
+///
+std::string TGParser::ParseObjectName() {
+ if (Lex.getCode() == tgtok::Id) {
+ std::string Ret = Lex.getCurStrVal();
+ Lex.Lex();
+ return Ret;
+ }
+
+ static unsigned AnonCounter = 0;
+ return "anonymous."+utostr(AnonCounter++);
+}
+
+
+/// ParseClassID - Parse and resolve a reference to a class name. This returns
+/// null on error.
+///
+/// ClassID ::= ID
+///
+Record *TGParser::ParseClassID() {
+ if (Lex.getCode() != tgtok::Id) {
+ TokError("expected name for ClassID");
+ return 0;
+ }
+
+ Record *Result = Records.getClass(Lex.getCurStrVal());
+ if (Result == 0)
+ TokError("Couldn't find class '" + Lex.getCurStrVal() + "'");
+
+ Lex.Lex();
+ return Result;
+}
+
+/// ParseMultiClassID - Parse and resolve a reference to a multiclass name.
+/// This returns null on error.
+///
+/// MultiClassID ::= ID
+///
+MultiClass *TGParser::ParseMultiClassID() {
+ if (Lex.getCode() != tgtok::Id) {
+ TokError("expected name for ClassID");
+ return 0;
+ }
+
+ MultiClass *Result = MultiClasses[Lex.getCurStrVal()];
+ if (Result == 0)
+ TokError("Couldn't find class '" + Lex.getCurStrVal() + "'");
+
+ Lex.Lex();
+ return Result;
+}
+
+Record *TGParser::ParseDefmID() {
+ if (Lex.getCode() != tgtok::Id) {
+ TokError("expected multiclass name");
+ return 0;
+ }
+
+ MultiClass *MC = MultiClasses[Lex.getCurStrVal()];
+ if (MC == 0) {
+ TokError("Couldn't find multiclass '" + Lex.getCurStrVal() + "'");
+ return 0;
+ }
+
+ Lex.Lex();
+ return &MC->Rec;
+}
+
+
+
+/// ParseSubClassReference - Parse a reference to a subclass or to a templated
+/// subclass. This returns a SubClassRefTy with a null Record* on error.
+///
+/// SubClassRef ::= ClassID
+/// SubClassRef ::= ClassID '<' ValueList '>'
+///
+SubClassReference TGParser::
+ParseSubClassReference(Record *CurRec, bool isDefm) {
+ SubClassReference Result;
+ Result.RefLoc = Lex.getLoc();
+
+ if (isDefm)
+ Result.Rec = ParseDefmID();
+ else
+ Result.Rec = ParseClassID();
+ if (Result.Rec == 0) return Result;
+
+ // If there is no template arg list, we're done.
+ if (Lex.getCode() != tgtok::less)
+ return Result;
+ Lex.Lex(); // Eat the '<'
+
+ if (Lex.getCode() == tgtok::greater) {
+ TokError("subclass reference requires a non-empty list of template values");
+ Result.Rec = 0;
+ return Result;
+ }
+
+ Result.TemplateArgs = ParseValueList(CurRec);
+ if (Result.TemplateArgs.empty()) {
+ Result.Rec = 0; // Error parsing value list.
+ return Result;
+ }
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected '>' in template value list");
+ Result.Rec = 0;
+ return Result;
+ }
+ Lex.Lex();
+
+ return Result;
+}
+
+/// ParseSubMultiClassReference - Parse a reference to a subclass or to a
+/// templated submulticlass. This returns a SubMultiClassRefTy with a null
+/// Record* on error.
+///
+/// SubMultiClassRef ::= MultiClassID
+/// SubMultiClassRef ::= MultiClassID '<' ValueList '>'
+///
+SubMultiClassReference TGParser::
+ParseSubMultiClassReference(MultiClass *CurMC) {
+ SubMultiClassReference Result;
+ Result.RefLoc = Lex.getLoc();
+
+ Result.MC = ParseMultiClassID();
+ if (Result.MC == 0) return Result;
+
+ // If there is no template arg list, we're done.
+ if (Lex.getCode() != tgtok::less)
+ return Result;
+ Lex.Lex(); // Eat the '<'
+
+ if (Lex.getCode() == tgtok::greater) {
+ TokError("subclass reference requires a non-empty list of template values");
+ Result.MC = 0;
+ return Result;
+ }
+
+ Result.TemplateArgs = ParseValueList(&CurMC->Rec);
+ if (Result.TemplateArgs.empty()) {
+ Result.MC = 0; // Error parsing value list.
+ return Result;
+ }
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected '>' in template value list");
+ Result.MC = 0;
+ return Result;
+ }
+ Lex.Lex();
+
+ return Result;
+}
+
+/// ParseRangePiece - Parse a bit/value range.
+/// RangePiece ::= INTVAL
+/// RangePiece ::= INTVAL '-' INTVAL
+/// RangePiece ::= INTVAL INTVAL
+bool TGParser::ParseRangePiece(std::vector<unsigned> &Ranges) {
+ if (Lex.getCode() != tgtok::IntVal) {
+ TokError("expected integer or bitrange");
+ return true;
+ }
+ int64_t Start = Lex.getCurIntVal();
+ int64_t End;
+
+ if (Start < 0)
+ return TokError("invalid range, cannot be negative");
+
+ switch (Lex.Lex()) { // eat first character.
+ default:
+ Ranges.push_back(Start);
+ return false;
+ case tgtok::minus:
+ if (Lex.Lex() != tgtok::IntVal) {
+ TokError("expected integer value as end of range");
+ return true;
+ }
+ End = Lex.getCurIntVal();
+ break;
+ case tgtok::IntVal:
+ End = -Lex.getCurIntVal();
+ break;
+ }
+ if (End < 0)
+ return TokError("invalid range, cannot be negative");
+ Lex.Lex();
+
+ // Add to the range.
+ if (Start < End) {
+ for (; Start <= End; ++Start)
+ Ranges.push_back(Start);
+ } else {
+ for (; Start >= End; --Start)
+ Ranges.push_back(Start);
+ }
+ return false;
+}
+
+/// ParseRangeList - Parse a list of scalars and ranges into scalar values.
+///
+/// RangeList ::= RangePiece (',' RangePiece)*
+///
+std::vector<unsigned> TGParser::ParseRangeList() {
+ std::vector<unsigned> Result;
+
+ // Parse the first piece.
+ if (ParseRangePiece(Result))
+ return std::vector<unsigned>();
+ while (Lex.getCode() == tgtok::comma) {
+ Lex.Lex(); // Eat the comma.
+
+ // Parse the next range piece.
+ if (ParseRangePiece(Result))
+ return std::vector<unsigned>();
+ }
+ return Result;
+}
+
+/// ParseOptionalRangeList - Parse either a range list in <>'s or nothing.
+/// OptionalRangeList ::= '<' RangeList '>'
+/// OptionalRangeList ::= /*empty*/
+bool TGParser::ParseOptionalRangeList(std::vector<unsigned> &Ranges) {
+ if (Lex.getCode() != tgtok::less)
+ return false;
+
+ TGLoc StartLoc = Lex.getLoc();
+ Lex.Lex(); // eat the '<'
+
+ // Parse the range list.
+ Ranges = ParseRangeList();
+ if (Ranges.empty()) return true;
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected '>' at end of range list");
+ return Error(StartLoc, "to match this '<'");
+ }
+ Lex.Lex(); // eat the '>'.
+ return false;
+}
+
+/// ParseOptionalBitList - Parse either a bit list in {}'s or nothing.
+/// OptionalBitList ::= '{' RangeList '}'
+/// OptionalBitList ::= /*empty*/
+bool TGParser::ParseOptionalBitList(std::vector<unsigned> &Ranges) {
+ if (Lex.getCode() != tgtok::l_brace)
+ return false;
+
+ TGLoc StartLoc = Lex.getLoc();
+ Lex.Lex(); // eat the '{'
+
+ // Parse the range list.
+ Ranges = ParseRangeList();
+ if (Ranges.empty()) return true;
+
+ if (Lex.getCode() != tgtok::r_brace) {
+ TokError("expected '}' at end of bit list");
+ return Error(StartLoc, "to match this '{'");
+ }
+ Lex.Lex(); // eat the '}'.
+ return false;
+}
+
+
+/// ParseType - Parse and return a tblgen type. This returns null on error.
+///
+/// Type ::= STRING // string type
+/// Type ::= BIT // bit type
+/// Type ::= BITS '<' INTVAL '>' // bits<x> type
+/// Type ::= INT // int type
+/// Type ::= LIST '<' Type '>' // list<x> type
+/// Type ::= CODE // code type
+/// Type ::= DAG // dag type
+/// Type ::= ClassID // Record Type
+///
+RecTy *TGParser::ParseType() {
+ switch (Lex.getCode()) {
+ default: TokError("Unknown token when expecting a type"); return 0;
+ case tgtok::String: Lex.Lex(); return new StringRecTy();
+ case tgtok::Bit: Lex.Lex(); return new BitRecTy();
+ case tgtok::Int: Lex.Lex(); return new IntRecTy();
+ case tgtok::Code: Lex.Lex(); return new CodeRecTy();
+ case tgtok::Dag: Lex.Lex(); return new DagRecTy();
+ case tgtok::Id:
+ if (Record *R = ParseClassID()) return new RecordRecTy(R);
+ return 0;
+ case tgtok::Bits: {
+ if (Lex.Lex() != tgtok::less) { // Eat 'bits'
+ TokError("expected '<' after bits type");
+ return 0;
+ }
+ if (Lex.Lex() != tgtok::IntVal) { // Eat '<'
+ TokError("expected integer in bits<n> type");
+ return 0;
+ }
+ uint64_t Val = Lex.getCurIntVal();
+ if (Lex.Lex() != tgtok::greater) { // Eat count.
+ TokError("expected '>' at end of bits<n> type");
+ return 0;
+ }
+ Lex.Lex(); // Eat '>'
+ return new BitsRecTy(Val);
+ }
+ case tgtok::List: {
+ if (Lex.Lex() != tgtok::less) { // Eat 'bits'
+ TokError("expected '<' after list type");
+ return 0;
+ }
+ Lex.Lex(); // Eat '<'
+ RecTy *SubType = ParseType();
+ if (SubType == 0) return 0;
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected '>' at end of list<ty> type");
+ return 0;
+ }
+ Lex.Lex(); // Eat '>'
+ return new ListRecTy(SubType);
+ }
+ }
+}
+
+/// ParseIDValue - Parse an ID as a value and decode what it means.
+///
+/// IDValue ::= ID [def local value]
+/// IDValue ::= ID [def template arg]
+/// IDValue ::= ID [multiclass local value]
+/// IDValue ::= ID [multiclass template argument]
+/// IDValue ::= ID [def name]
+///
+Init *TGParser::ParseIDValue(Record *CurRec) {
+ assert(Lex.getCode() == tgtok::Id && "Expected ID in ParseIDValue");
+ std::string Name = Lex.getCurStrVal();
+ TGLoc Loc = Lex.getLoc();
+ Lex.Lex();
+ return ParseIDValue(CurRec, Name, Loc);
+}
+
+/// ParseIDValue - This is just like ParseIDValue above, but it assumes the ID
+/// has already been read.
+Init *TGParser::ParseIDValue(Record *CurRec,
+ const std::string &Name, TGLoc NameLoc) {
+ if (CurRec) {
+ if (const RecordVal *RV = CurRec->getValue(Name))
+ return new VarInit(Name, RV->getType());
+
+ std::string TemplateArgName = CurRec->getName()+":"+Name;
+ if (CurRec->isTemplateArg(TemplateArgName)) {
+ const RecordVal *RV = CurRec->getValue(TemplateArgName);
+ assert(RV && "Template arg doesn't exist??");
+ return new VarInit(TemplateArgName, RV->getType());
+ }
+ }
+
+ if (CurMultiClass) {
+ std::string MCName = CurMultiClass->Rec.getName()+"::"+Name;
+ if (CurMultiClass->Rec.isTemplateArg(MCName)) {
+ const RecordVal *RV = CurMultiClass->Rec.getValue(MCName);
+ assert(RV && "Template arg doesn't exist??");
+ return new VarInit(MCName, RV->getType());
+ }
+ }
+
+ if (Record *D = Records.getDef(Name))
+ return new DefInit(D);
+
+ Error(NameLoc, "Variable not defined: '" + Name + "'");
+ return 0;
+}
+
+/// ParseOperation - Parse an operator. This returns null on error.
+///
+/// Operation ::= XOperator ['<' Type '>'] '(' Args ')'
+///
+Init *TGParser::ParseOperation(Record *CurRec) {
+ switch (Lex.getCode()) {
+ default:
+ TokError("unknown operation");
+ return 0;
+ break;
+ case tgtok::XCar:
+ case tgtok::XCdr:
+ case tgtok::XNull:
+ case tgtok::XCast: { // Value ::= !unop '(' Value ')'
+ UnOpInit::UnaryOp Code;
+ RecTy *Type = 0;
+
+ switch (Lex.getCode()) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XCast:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::CAST;
+
+ Type = ParseOperatorType();
+
+ if (Type == 0) {
+ TokError("did not get type for unary operator");
+ return 0;
+ }
+
+ break;
+ case tgtok::XCar:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::CAR;
+ break;
+ case tgtok::XCdr:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::CDR;
+ break;
+ case tgtok::XNull:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::LNULL;
+ Type = new IntRecTy;
+ break;
+ }
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after unary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the '('
+
+ Init *LHS = ParseValue(CurRec);
+ if (LHS == 0) return 0;
+
+ if (Code == UnOpInit::CAR
+ || Code == UnOpInit::CDR
+ || Code == UnOpInit::LNULL) {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS);
+ if (LHSl == 0 && LHSt == 0) {
+ TokError("expected list type argument in unary operator");
+ return 0;
+ }
+ if (LHSt) {
+ ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType());
+ if (LType == 0) {
+ TokError("expected list type argumnet in unary operator");
+ return 0;
+ }
+ }
+
+ if (Code == UnOpInit::CAR
+ || Code == UnOpInit::CDR) {
+ if (LHSl && LHSl->getSize() == 0) {
+ TokError("empty list argument in unary operator");
+ return 0;
+ }
+ if (LHSl) {
+ Init *Item = LHSl->getElement(0);
+ TypedInit *Itemt = dynamic_cast<TypedInit*>(Item);
+ if (Itemt == 0) {
+ TokError("untyped list element in unary operator");
+ return 0;
+ }
+ if (Code == UnOpInit::CAR) {
+ Type = Itemt->getType();
+ }
+ else {
+ Type = new ListRecTy(Itemt->getType());
+ }
+ }
+ else {
+ assert(LHSt && "expected list type argument in unary operator");
+ ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType());
+ if (LType == 0) {
+ TokError("expected list type argumnet in unary operator");
+ return 0;
+ }
+ if (Code == UnOpInit::CAR) {
+ Type = LType->getElementType();
+ }
+ else {
+ Type = LType;
+ }
+ }
+ }
+ }
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in unary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+ return (new UnOpInit(Code, LHS, Type))->Fold(CurRec, CurMultiClass);
+ }
+
+ case tgtok::XConcat:
+ case tgtok::XSRA:
+ case tgtok::XSRL:
+ case tgtok::XSHL:
+ case tgtok::XStrConcat:
+ case tgtok::XNameConcat: { // Value ::= !binop '(' Value ',' Value ')'
+ BinOpInit::BinaryOp Code;
+ RecTy *Type = 0;
+
+
+ switch (Lex.getCode()) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XConcat:
+ Lex.Lex(); // eat the operation
+ Code = BinOpInit::CONCAT;
+ Type = new DagRecTy();
+ break;
+ case tgtok::XSRA:
+ Lex.Lex(); // eat the operation
+ Code = BinOpInit::SRA;
+ Type = new IntRecTy();
+ break;
+ case tgtok::XSRL:
+ Lex.Lex(); // eat the operation
+ Code = BinOpInit::SRL;
+ Type = new IntRecTy();
+ break;
+ case tgtok::XSHL:
+ Lex.Lex(); // eat the operation
+ Code = BinOpInit::SHL;
+ Type = new IntRecTy();
+ break;
+ case tgtok::XStrConcat:
+ Lex.Lex(); // eat the operation
+ Code = BinOpInit::STRCONCAT;
+ Type = new StringRecTy();
+ break;
+ case tgtok::XNameConcat:
+ Lex.Lex(); // eat the operation
+ Code = BinOpInit::NAMECONCAT;
+
+ Type = ParseOperatorType();
+
+ if (Type == 0) {
+ TokError("did not get type for binary operator");
+ return 0;
+ }
+
+ break;
+ }
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after binary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the '('
+
+ Init *LHS = ParseValue(CurRec);
+ if (LHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::comma) {
+ TokError("expected ',' in binary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ','
+
+ Init *RHS = ParseValue(CurRec);
+ if (RHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in binary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+ return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass);
+ }
+
+ case tgtok::XIf:
+ case tgtok::XForEach:
+ case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
+ TernOpInit::TernaryOp Code;
+ RecTy *Type = 0;
+
+
+ tgtok::TokKind LexCode = Lex.getCode();
+ Lex.Lex(); // eat the operation
+ switch (LexCode) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XIf:
+ Code = TernOpInit::IF;
+ break;
+ case tgtok::XForEach:
+ Code = TernOpInit::FOREACH;
+ break;
+ case tgtok::XSubst:
+ Code = TernOpInit::SUBST;
+ break;
+ }
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after ternary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the '('
+
+ Init *LHS = ParseValue(CurRec);
+ if (LHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::comma) {
+ TokError("expected ',' in ternary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ','
+
+ Init *MHS = ParseValue(CurRec);
+ if (MHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::comma) {
+ TokError("expected ',' in ternary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ','
+
+ Init *RHS = ParseValue(CurRec);
+ if (RHS == 0) return 0;
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in binary operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+
+ switch (LexCode) {
+ default: assert(0 && "Unhandled code!");
+ case tgtok::XIf: {
+ TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS);
+ TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS);
+ if (MHSt == 0 || RHSt == 0) {
+ TokError("could not get type for !if");
+ return 0;
+ }
+ if (MHSt->getType()->typeIsConvertibleTo(RHSt->getType())) {
+ Type = RHSt->getType();
+ }
+ else if (RHSt->getType()->typeIsConvertibleTo(MHSt->getType())) {
+ Type = MHSt->getType();
+ }
+ else {
+ TokError("inconsistent types for !if");
+ return 0;
+ }
+ break;
+ }
+ case tgtok::XForEach: {
+ TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS);
+ if (MHSt == 0) {
+ TokError("could not get type for !foreach");
+ return 0;
+ }
+ Type = MHSt->getType();
+ break;
+ }
+ case tgtok::XSubst: {
+ TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS);
+ if (RHSt == 0) {
+ TokError("could not get type for !subst");
+ return 0;
+ }
+ Type = RHSt->getType();
+ break;
+ }
+ }
+ return (new TernOpInit(Code, LHS, MHS, RHS, Type))->Fold(CurRec, CurMultiClass);
+ }
+ }
+ TokError("could not parse operation");
+ return 0;
+}
+
+/// ParseOperatorType - Parse a type for an operator. This returns
+/// null on error.
+///
+/// OperatorType ::= '<' Type '>'
+///
+RecTy *TGParser::ParseOperatorType(void) {
+ RecTy *Type = 0;
+
+ if (Lex.getCode() != tgtok::less) {
+ TokError("expected type name for operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the <
+
+ Type = ParseType();
+
+ if (Type == 0) {
+ TokError("expected type name for operator");
+ return 0;
+ }
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected type name for operator");
+ return 0;
+ }
+ Lex.Lex(); // eat the >
+
+ return Type;
+}
+
+
+/// ParseSimpleValue - Parse a tblgen value. This returns null on error.
+///
+/// SimpleValue ::= IDValue
+/// SimpleValue ::= INTVAL
+/// SimpleValue ::= STRVAL+
+/// SimpleValue ::= CODEFRAGMENT
+/// SimpleValue ::= '?'
+/// SimpleValue ::= '{' ValueList '}'
+/// SimpleValue ::= ID '<' ValueListNE '>'
+/// SimpleValue ::= '[' ValueList ']'
+/// SimpleValue ::= '(' IDValue DagArgList ')'
+/// SimpleValue ::= CONCATTOK '(' Value ',' Value ')'
+/// SimpleValue ::= SHLTOK '(' Value ',' Value ')'
+/// SimpleValue ::= SRATOK '(' Value ',' Value ')'
+/// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
+/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
+///
+Init *TGParser::ParseSimpleValue(Record *CurRec) {
+ Init *R = 0;
+ switch (Lex.getCode()) {
+ default: TokError("Unknown token when parsing a value"); break;
+ case tgtok::IntVal: R = new IntInit(Lex.getCurIntVal()); Lex.Lex(); break;
+ case tgtok::StrVal: {
+ std::string Val = Lex.getCurStrVal();
+ Lex.Lex();
+
+ // Handle multiple consecutive concatenated strings.
+ while (Lex.getCode() == tgtok::StrVal) {
+ Val += Lex.getCurStrVal();
+ Lex.Lex();
+ }
+
+ R = new StringInit(Val);
+ break;
+ }
+ case tgtok::CodeFragment:
+ R = new CodeInit(Lex.getCurStrVal()); Lex.Lex(); break;
+ case tgtok::question: R = new UnsetInit(); Lex.Lex(); break;
+ case tgtok::Id: {
+ TGLoc NameLoc = Lex.getLoc();
+ std::string Name = Lex.getCurStrVal();
+ if (Lex.Lex() != tgtok::less) // consume the Id.
+ return ParseIDValue(CurRec, Name, NameLoc); // Value ::= IDValue
+
+ // Value ::= ID '<' ValueListNE '>'
+ if (Lex.Lex() == tgtok::greater) {
+ TokError("expected non-empty value list");
+ return 0;
+ }
+ std::vector<Init*> ValueList = ParseValueList(CurRec);
+ if (ValueList.empty()) return 0;
+
+ if (Lex.getCode() != tgtok::greater) {
+ TokError("expected '>' at end of value list");
+ return 0;
+ }
+ Lex.Lex(); // eat the '>'
+
+ // 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(Name);
+ if (!Class) {
+ Error(NameLoc, "Expected a class name, got '" + Name + "'");
+ return 0;
+ }
+
+ // Create the new record, set it as CurRec temporarily.
+ static unsigned AnonCounter = 0;
+ Record *NewRec = new Record("anonymous.val."+utostr(AnonCounter++),NameLoc);
+ SubClassReference SCRef;
+ SCRef.RefLoc = NameLoc;
+ SCRef.Rec = Class;
+ SCRef.TemplateArgs = ValueList;
+ // Add info about the subclass to NewRec.
+ if (AddSubClass(NewRec, SCRef))
+ return 0;
+ NewRec->resolveReferences();
+ Records.addDef(NewRec);
+
+ // The result of the expression is a reference to the new record.
+ return new DefInit(NewRec);
+ }
+ case tgtok::l_brace: { // Value ::= '{' ValueList '}'
+ TGLoc BraceLoc = Lex.getLoc();
+ Lex.Lex(); // eat the '{'
+ std::vector<Init*> Vals;
+
+ if (Lex.getCode() != tgtok::r_brace) {
+ Vals = ParseValueList(CurRec);
+ if (Vals.empty()) return 0;
+ }
+ if (Lex.getCode() != tgtok::r_brace) {
+ TokError("expected '}' at end of bit list value");
+ return 0;
+ }
+ Lex.Lex(); // eat the '}'
+
+ BitsInit *Result = new BitsInit(Vals.size());
+ for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
+ Init *Bit = Vals[i]->convertInitializerTo(new BitRecTy());
+ if (Bit == 0) {
+ Error(BraceLoc, "Element #" + utostr(i) + " (" + Vals[i]->getAsString()+
+ ") is not convertable to a bit");
+ return 0;
+ }
+ Result->setBit(Vals.size()-i-1, Bit);
+ }
+ return Result;
+ }
+ case tgtok::l_square: { // Value ::= '[' ValueList ']'
+ Lex.Lex(); // eat the '['
+ std::vector<Init*> Vals;
+
+ if (Lex.getCode() != tgtok::r_square) {
+ Vals = ParseValueList(CurRec);
+ if (Vals.empty()) return 0;
+ }
+ if (Lex.getCode() != tgtok::r_square) {
+ TokError("expected ']' at end of list value");
+ return 0;
+ }
+ Lex.Lex(); // eat the ']'
+ return new ListInit(Vals);
+ }
+ case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
+ Lex.Lex(); // eat the '('
+ if (Lex.getCode() != tgtok::Id
+ && Lex.getCode() != tgtok::XCast
+ && Lex.getCode() != tgtok::XNameConcat) {
+ TokError("expected identifier in dag init");
+ return 0;
+ }
+
+ Init *Operator = 0;
+ if (Lex.getCode() == tgtok::Id) {
+ Operator = ParseIDValue(CurRec);
+ if (Operator == 0) return 0;
+ }
+ else {
+ Operator = ParseOperation(CurRec);
+ if (Operator == 0) return 0;
+ }
+
+ // If the operator name is present, parse it.
+ std::string OperatorName;
+ if (Lex.getCode() == tgtok::colon) {
+ if (Lex.Lex() != tgtok::VarName) { // eat the ':'
+ TokError("expected variable name in dag operator");
+ return 0;
+ }
+ OperatorName = Lex.getCurStrVal();
+ Lex.Lex(); // eat the VarName.
+ }
+
+ std::vector<std::pair<llvm::Init*, std::string> > DagArgs;
+ if (Lex.getCode() != tgtok::r_paren) {
+ DagArgs = ParseDagArgList(CurRec);
+ if (DagArgs.empty()) return 0;
+ }
+
+ if (Lex.getCode() != tgtok::r_paren) {
+ TokError("expected ')' in dag init");
+ return 0;
+ }
+ Lex.Lex(); // eat the ')'
+
+ return new DagInit(Operator, OperatorName, DagArgs);
+ break;
+ }
+
+ case tgtok::XCar:
+ case tgtok::XCdr:
+ case tgtok::XNull:
+ case tgtok::XCast: // Value ::= !unop '(' Value ')'
+ case tgtok::XConcat:
+ case tgtok::XSRA:
+ case tgtok::XSRL:
+ case tgtok::XSHL:
+ case tgtok::XStrConcat:
+ case tgtok::XNameConcat: // Value ::= !binop '(' Value ',' Value ')'
+ case tgtok::XIf:
+ case tgtok::XForEach:
+ case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
+ return ParseOperation(CurRec);
+ break;
+ }
+ }
+
+ return R;
+}
+
+/// ParseValue - Parse a tblgen value. This returns null on error.
+///
+/// Value ::= SimpleValue ValueSuffix*
+/// ValueSuffix ::= '{' BitList '}'
+/// ValueSuffix ::= '[' BitList ']'
+/// ValueSuffix ::= '.' ID
+///
+Init *TGParser::ParseValue(Record *CurRec) {
+ Init *Result = ParseSimpleValue(CurRec);
+ if (Result == 0) return 0;
+
+ // Parse the suffixes now if present.
+ while (1) {
+ switch (Lex.getCode()) {
+ default: return Result;
+ case tgtok::l_brace: {
+ TGLoc CurlyLoc = Lex.getLoc();
+ Lex.Lex(); // eat the '{'
+ std::vector<unsigned> Ranges = ParseRangeList();
+ if (Ranges.empty()) return 0;
+
+ // Reverse the bitlist.
+ std::reverse(Ranges.begin(), Ranges.end());
+ Result = Result->convertInitializerBitRange(Ranges);
+ if (Result == 0) {
+ Error(CurlyLoc, "Invalid bit range for value");
+ return 0;
+ }
+
+ // Eat the '}'.
+ if (Lex.getCode() != tgtok::r_brace) {
+ TokError("expected '}' at end of bit range list");
+ return 0;
+ }
+ Lex.Lex();
+ break;
+ }
+ case tgtok::l_square: {
+ TGLoc SquareLoc = Lex.getLoc();
+ Lex.Lex(); // eat the '['
+ std::vector<unsigned> Ranges = ParseRangeList();
+ if (Ranges.empty()) return 0;
+
+ Result = Result->convertInitListSlice(Ranges);
+ if (Result == 0) {
+ Error(SquareLoc, "Invalid range for list slice");
+ return 0;
+ }
+
+ // Eat the ']'.
+ if (Lex.getCode() != tgtok::r_square) {
+ TokError("expected ']' at end of list slice");
+ return 0;
+ }
+ Lex.Lex();
+ break;
+ }
+ case tgtok::period:
+ if (Lex.Lex() != tgtok::Id) { // eat the .
+ TokError("expected field identifier after '.'");
+ return 0;
+ }
+ if (!Result->getFieldType(Lex.getCurStrVal())) {
+ TokError("Cannot access field '" + Lex.getCurStrVal() + "' of value '" +
+ Result->getAsString() + "'");
+ return 0;
+ }
+ Result = new FieldInit(Result, Lex.getCurStrVal());
+ Lex.Lex(); // eat field name
+ break;
+ }
+ }
+}
+
+/// ParseDagArgList - Parse the argument list for a dag literal expression.
+///
+/// ParseDagArgList ::= Value (':' VARNAME)?
+/// ParseDagArgList ::= ParseDagArgList ',' Value (':' VARNAME)?
+std::vector<std::pair<llvm::Init*, std::string> >
+TGParser::ParseDagArgList(Record *CurRec) {
+ std::vector<std::pair<llvm::Init*, std::string> > Result;
+
+ while (1) {
+ Init *Val = ParseValue(CurRec);
+ if (Val == 0) return std::vector<std::pair<llvm::Init*, std::string> >();
+
+ // If the variable name is present, add it.
+ std::string VarName;
+ if (Lex.getCode() == tgtok::colon) {
+ if (Lex.Lex() != tgtok::VarName) { // eat the ':'
+ TokError("expected variable name in dag literal");
+ return std::vector<std::pair<llvm::Init*, std::string> >();
+ }
+ VarName = Lex.getCurStrVal();
+ Lex.Lex(); // eat the VarName.
+ }
+
+ Result.push_back(std::make_pair(Val, VarName));
+
+ if (Lex.getCode() != tgtok::comma) break;
+ Lex.Lex(); // eat the ','
+ }
+
+ return Result;
+}
+
+
+/// ParseValueList - Parse a comma separated list of values, returning them as a
+/// vector. Note that this always expects to be able to parse at least one
+/// value. It returns an empty list if this is not possible.
+///
+/// ValueList ::= Value (',' Value)
+///
+std::vector<Init*> TGParser::ParseValueList(Record *CurRec) {
+ std::vector<Init*> Result;
+ Result.push_back(ParseValue(CurRec));
+ if (Result.back() == 0) return std::vector<Init*>();
+
+ while (Lex.getCode() == tgtok::comma) {
+ Lex.Lex(); // Eat the comma
+
+ Result.push_back(ParseValue(CurRec));
+ if (Result.back() == 0) return std::vector<Init*>();
+ }
+
+ return Result;
+}
+
+
+
+/// ParseDeclaration - Read a declaration, returning the name of field ID, or an
+/// empty string on error. This can happen in a number of different context's,
+/// including within a def or in the template args for a def (which which case
+/// CurRec will be non-null) and within the template args for a multiclass (in
+/// which case CurRec will be null, but CurMultiClass will be set). This can
+/// also happen within a def that is within a multiclass, which will set both
+/// CurRec and CurMultiClass.
+///
+/// Declaration ::= FIELD? Type ID ('=' Value)?
+///
+std::string TGParser::ParseDeclaration(Record *CurRec,
+ bool ParsingTemplateArgs) {
+ // Read the field prefix if present.
+ bool HasField = Lex.getCode() == tgtok::Field;
+ if (HasField) Lex.Lex();
+
+ RecTy *Type = ParseType();
+ if (Type == 0) return "";
+
+ if (Lex.getCode() != tgtok::Id) {
+ TokError("Expected identifier in declaration");
+ return "";
+ }
+
+ TGLoc IdLoc = Lex.getLoc();
+ std::string DeclName = Lex.getCurStrVal();
+ Lex.Lex();
+
+ if (ParsingTemplateArgs) {
+ if (CurRec) {
+ DeclName = CurRec->getName() + ":" + DeclName;
+ } else {
+ assert(CurMultiClass);
+ }
+ if (CurMultiClass)
+ DeclName = CurMultiClass->Rec.getName() + "::" + DeclName;
+ }
+
+ // Add the value.
+ if (AddValue(CurRec, IdLoc, RecordVal(DeclName, Type, HasField)))
+ return "";
+
+ // If a value is present, parse it.
+ if (Lex.getCode() == tgtok::equal) {
+ Lex.Lex();
+ TGLoc ValLoc = Lex.getLoc();
+ Init *Val = ParseValue(CurRec);
+ if (Val == 0 ||
+ SetValue(CurRec, ValLoc, DeclName, std::vector<unsigned>(), Val))
+ return "";
+ }
+
+ return DeclName;
+}
+
+/// ParseTemplateArgList - Read a template argument list, which is a non-empty
+/// sequence of template-declarations in <>'s. If CurRec is non-null, these are
+/// template args for a def, which may or may not be in a multiclass. If null,
+/// these are the template args for a multiclass.
+///
+/// TemplateArgList ::= '<' Declaration (',' Declaration)* '>'
+///
+bool TGParser::ParseTemplateArgList(Record *CurRec) {
+ assert(Lex.getCode() == tgtok::less && "Not a template arg list!");
+ Lex.Lex(); // eat the '<'
+
+ Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec;
+
+ // Read the first declaration.
+ std::string TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
+ if (TemplArg.empty())
+ return true;
+
+ TheRecToAddTo->addTemplateArg(TemplArg);
+
+ while (Lex.getCode() == tgtok::comma) {
+ Lex.Lex(); // eat the ','
+
+ // Read the following declarations.
+ TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
+ if (TemplArg.empty())
+ return true;
+ TheRecToAddTo->addTemplateArg(TemplArg);
+ }
+
+ if (Lex.getCode() != tgtok::greater)
+ return TokError("expected '>' at end of template argument list");
+ Lex.Lex(); // eat the '>'.
+ return false;
+}
+
+
+/// ParseBodyItem - Parse a single item at within the body of a def or class.
+///
+/// BodyItem ::= Declaration ';'
+/// BodyItem ::= LET ID OptionalBitList '=' Value ';'
+bool TGParser::ParseBodyItem(Record *CurRec) {
+ if (Lex.getCode() != tgtok::Let) {
+ if (ParseDeclaration(CurRec, false).empty())
+ return true;
+
+ if (Lex.getCode() != tgtok::semi)
+ return TokError("expected ';' after declaration");
+ Lex.Lex();
+ return false;
+ }
+
+ // LET ID OptionalRangeList '=' Value ';'
+ if (Lex.Lex() != tgtok::Id)
+ return TokError("expected field identifier after let");
+
+ TGLoc IdLoc = Lex.getLoc();
+ std::string FieldName = Lex.getCurStrVal();
+ Lex.Lex(); // eat the field name.
+
+ std::vector<unsigned> BitList;
+ if (ParseOptionalBitList(BitList))
+ return true;
+ std::reverse(BitList.begin(), BitList.end());
+
+ if (Lex.getCode() != tgtok::equal)
+ return TokError("expected '=' in let expression");
+ Lex.Lex(); // eat the '='.
+
+ Init *Val = ParseValue(CurRec);
+ if (Val == 0) return true;
+
+ if (Lex.getCode() != tgtok::semi)
+ return TokError("expected ';' after let expression");
+ Lex.Lex();
+
+ return SetValue(CurRec, IdLoc, FieldName, BitList, Val);
+}
+
+/// ParseBody - Read the body of a class or def. Return true on error, false on
+/// success.
+///
+/// Body ::= ';'
+/// Body ::= '{' BodyList '}'
+/// BodyList BodyItem*
+///
+bool TGParser::ParseBody(Record *CurRec) {
+ // If this is a null definition, just eat the semi and return.
+ if (Lex.getCode() == tgtok::semi) {
+ Lex.Lex();
+ return false;
+ }
+
+ if (Lex.getCode() != tgtok::l_brace)
+ return TokError("Expected ';' or '{' to start body");
+ // Eat the '{'.
+ Lex.Lex();
+
+ while (Lex.getCode() != tgtok::r_brace)
+ if (ParseBodyItem(CurRec))
+ return true;
+
+ // Eat the '}'.
+ Lex.Lex();
+ return false;
+}
+
+/// ParseObjectBody - Parse the body of a def or class. This consists of an
+/// optional ClassList followed by a Body. CurRec is the current def or class
+/// that is being parsed.
+///
+/// ObjectBody ::= BaseClassList Body
+/// BaseClassList ::= /*empty*/
+/// BaseClassList ::= ':' BaseClassListNE
+/// BaseClassListNE ::= SubClassRef (',' SubClassRef)*
+///
+bool TGParser::ParseObjectBody(Record *CurRec) {
+ // If there is a baseclass list, read it.
+ if (Lex.getCode() == tgtok::colon) {
+ Lex.Lex();
+
+ // Read all of the subclasses.
+ SubClassReference SubClass = ParseSubClassReference(CurRec, false);
+ while (1) {
+ // Check for error.
+ if (SubClass.Rec == 0) return true;
+
+ // Add it.
+ if (AddSubClass(CurRec, SubClass))
+ return true;
+
+ if (Lex.getCode() != tgtok::comma) break;
+ Lex.Lex(); // eat ','.
+ SubClass = ParseSubClassReference(CurRec, false);
+ }
+ }
+
+ // 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)
+ if (SetValue(CurRec, LetStack[i][j].Loc, LetStack[i][j].Name,
+ LetStack[i][j].Bits, LetStack[i][j].Value))
+ return true;
+
+ return ParseBody(CurRec);
+}
+
+
+/// ParseDef - Parse and return a top level or multiclass def, return the record
+/// corresponding to it. This returns null on error.
+///
+/// DefInst ::= DEF ObjectName ObjectBody
+///
+llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) {
+ TGLoc DefLoc = Lex.getLoc();
+ assert(Lex.getCode() == tgtok::Def && "Unknown tok");
+ Lex.Lex(); // Eat the 'def' token.
+
+ // Parse ObjectName and make a record for it.
+ Record *CurRec = new Record(ParseObjectName(), DefLoc);
+
+ if (!CurMultiClass) {
+ // Top-level def definition.
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ Error(DefLoc, "def '" + CurRec->getName() + "' already defined");
+ return 0;
+ }
+ 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()) {
+ Error(DefLoc, "def '" + CurRec->getName() +
+ "' already defined in this multiclass!");
+ return 0;
+ }
+ CurMultiClass->DefPrototypes.push_back(CurRec);
+ }
+
+ if (ParseObjectBody(CurRec))
+ return 0;
+
+ if (CurMultiClass == 0) // Def's in multiclasses aren't really defs.
+ CurRec->resolveReferences();
+
+ // If ObjectBody has template arguments, it's an error.
+ assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?");
+ return CurRec;
+}
+
+
+/// ParseClass - Parse a tblgen class definition.
+///
+/// ClassInst ::= CLASS ID TemplateArgList? ObjectBody
+///
+bool TGParser::ParseClass() {
+ assert(Lex.getCode() == tgtok::Class && "Unexpected token!");
+ Lex.Lex();
+
+ if (Lex.getCode() != tgtok::Id)
+ return TokError("expected class name after 'class' keyword");
+
+ Record *CurRec = Records.getClass(Lex.getCurStrVal());
+ if (CurRec) {
+ // If the body was previously defined, this is an error.
+ if (!CurRec->getValues().empty() ||
+ !CurRec->getSuperClasses().empty() ||
+ !CurRec->getTemplateArgs().empty())
+ return TokError("Class '" + CurRec->getName() + "' already defined");
+ } else {
+ // If this is the first reference to this class, create and add it.
+ CurRec = new Record(Lex.getCurStrVal(), Lex.getLoc());
+ Records.addClass(CurRec);
+ }
+ Lex.Lex(); // eat the name.
+
+ // If there are template args, parse them.
+ if (Lex.getCode() == tgtok::less)
+ if (ParseTemplateArgList(CurRec))
+ return true;
+
+ // Finally, parse the object body.
+ return ParseObjectBody(CurRec);
+}
+
+/// ParseLetList - Parse a non-empty list of assignment expressions into a list
+/// of LetRecords.
+///
+/// LetList ::= LetItem (',' LetItem)*
+/// LetItem ::= ID OptionalRangeList '=' Value
+///
+std::vector<LetRecord> TGParser::ParseLetList() {
+ std::vector<LetRecord> Result;
+
+ while (1) {
+ if (Lex.getCode() != tgtok::Id) {
+ TokError("expected identifier in let definition");
+ return std::vector<LetRecord>();
+ }
+ std::string Name = Lex.getCurStrVal();
+ TGLoc NameLoc = Lex.getLoc();
+ Lex.Lex(); // Eat the identifier.
+
+ // Check for an optional RangeList.
+ std::vector<unsigned> Bits;
+ if (ParseOptionalRangeList(Bits))
+ return std::vector<LetRecord>();
+ std::reverse(Bits.begin(), Bits.end());
+
+ if (Lex.getCode() != tgtok::equal) {
+ TokError("expected '=' in let expression");
+ return std::vector<LetRecord>();
+ }
+ Lex.Lex(); // eat the '='.
+
+ Init *Val = ParseValue(0);
+ if (Val == 0) return std::vector<LetRecord>();
+
+ // Now that we have everything, add the record.
+ Result.push_back(LetRecord(Name, Bits, Val, NameLoc));
+
+ if (Lex.getCode() != tgtok::comma)
+ return Result;
+ Lex.Lex(); // eat the comma.
+ }
+}
+
+/// ParseTopLevelLet - Parse a 'let' at top level. This can be a couple of
+/// different related productions.
+///
+/// Object ::= LET LetList IN '{' ObjectList '}'
+/// Object ::= LET LetList IN Object
+///
+bool TGParser::ParseTopLevelLet() {
+ assert(Lex.getCode() == tgtok::Let && "Unexpected token");
+ Lex.Lex();
+
+ // Add this entry to the let stack.
+ std::vector<LetRecord> LetInfo = ParseLetList();
+ if (LetInfo.empty()) return true;
+ LetStack.push_back(LetInfo);
+
+ if (Lex.getCode() != tgtok::In)
+ return TokError("expected 'in' at end of top-level 'let'");
+ Lex.Lex();
+
+ // If this is a scalar let, just handle it now
+ if (Lex.getCode() != tgtok::l_brace) {
+ // LET LetList IN Object
+ if (ParseObject())
+ return true;
+ } else { // Object ::= LETCommand '{' ObjectList '}'
+ TGLoc BraceLoc = Lex.getLoc();
+ // Otherwise, this is a group let.
+ Lex.Lex(); // eat the '{'.
+
+ // Parse the object list.
+ if (ParseObjectList())
+ return true;
+
+ if (Lex.getCode() != tgtok::r_brace) {
+ TokError("expected '}' at end of top level let command");
+ return Error(BraceLoc, "to match this '{'");
+ }
+ Lex.Lex();
+ }
+
+ // Outside this let scope, this let block is not active.
+ LetStack.pop_back();
+ return false;
+}
+
+/// ParseMultiClassDef - Parse a def in a multiclass context.
+///
+/// MultiClassDef ::= DefInst
+///
+bool TGParser::ParseMultiClassDef(MultiClass *CurMC) {
+ if (Lex.getCode() != tgtok::Def)
+ return TokError("expected 'def' in multiclass body");
+
+ Record *D = ParseDef(CurMC);
+ if (D == 0) return true;
+
+ // Copy the template arguments for the multiclass into the def.
+ const std::vector<std::string> &TArgs = CurMC->Rec.getTemplateArgs();
+
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ const RecordVal *RV = CurMC->Rec.getValue(TArgs[i]);
+ assert(RV && "Template arg doesn't exist?");
+ D->addValue(*RV);
+ }
+
+ return false;
+}
+
+/// ParseMultiClass - Parse a multiclass definition.
+///
+/// MultiClassInst ::= MULTICLASS ID TemplateArgList?
+/// ':' BaseMultiClassList '{' MultiClassDef+ '}'
+///
+bool TGParser::ParseMultiClass() {
+ assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token");
+ Lex.Lex(); // Eat the multiclass token.
+
+ if (Lex.getCode() != tgtok::Id)
+ return TokError("expected identifier after multiclass for name");
+ std::string Name = Lex.getCurStrVal();
+
+ if (MultiClasses.count(Name))
+ return TokError("multiclass '" + Name + "' already defined");
+
+ CurMultiClass = MultiClasses[Name] = new MultiClass(Name, Lex.getLoc());
+ Lex.Lex(); // Eat the identifier.
+
+ // If there are template args, parse them.
+ if (Lex.getCode() == tgtok::less)
+ if (ParseTemplateArgList(0))
+ return true;
+
+ bool inherits = false;
+
+ // If there are submulticlasses, parse them.
+ if (Lex.getCode() == tgtok::colon) {
+ inherits = true;
+
+ Lex.Lex();
+
+ // Read all of the submulticlasses.
+ SubMultiClassReference SubMultiClass =
+ ParseSubMultiClassReference(CurMultiClass);
+ while (1) {
+ // Check for error.
+ if (SubMultiClass.MC == 0) return true;
+
+ // Add it.
+ if (AddSubMultiClass(CurMultiClass, SubMultiClass))
+ return true;
+
+ if (Lex.getCode() != tgtok::comma) break;
+ Lex.Lex(); // eat ','.
+ SubMultiClass = ParseSubMultiClassReference(CurMultiClass);
+ }
+ }
+
+ if (Lex.getCode() != tgtok::l_brace) {
+ if (!inherits)
+ return TokError("expected '{' in multiclass definition");
+ else
+ if (Lex.getCode() != tgtok::semi)
+ return TokError("expected ';' in multiclass definition");
+ else
+ Lex.Lex(); // eat the ';'.
+ }
+ else {
+ if (Lex.Lex() == tgtok::r_brace) // eat the '{'.
+ return TokError("multiclass must contain at least one def");
+
+ while (Lex.getCode() != tgtok::r_brace)
+ if (ParseMultiClassDef(CurMultiClass))
+ return true;
+
+ Lex.Lex(); // eat the '}'.
+ }
+
+ CurMultiClass = 0;
+ return false;
+}
+
+/// ParseDefm - Parse the instantiation of a multiclass.
+///
+/// DefMInst ::= DEFM ID ':' DefmSubClassRef ';'
+///
+bool TGParser::ParseDefm() {
+ assert(Lex.getCode() == tgtok::Defm && "Unexpected token!");
+ if (Lex.Lex() != tgtok::Id) // eat the defm.
+ return TokError("expected identifier after defm");
+
+ TGLoc DefmPrefixLoc = Lex.getLoc();
+ std::string DefmPrefix = Lex.getCurStrVal();
+ if (Lex.Lex() != tgtok::colon)
+ return TokError("expected ':' after defm identifier");
+
+ // eat the colon.
+ Lex.Lex();
+
+ TGLoc SubClassLoc = Lex.getLoc();
+ SubClassReference Ref = ParseSubClassReference(0, true);
+
+ while (1) {
+ if (Ref.Rec == 0) return true;
+
+ // 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[Ref.Rec->getName()];
+ assert(MC && "Didn't lookup multiclass correctly?");
+ std::vector<Init*> &TemplateVals = Ref.TemplateArgs;
+
+ // Verify that the correct number of template arguments were specified.
+ const std::vector<std::string> &TArgs = MC->Rec.getTemplateArgs();
+ if (TArgs.size() < TemplateVals.size())
+ return Error(SubClassLoc,
+ "more template args specified than multiclass expects");
+
+ // 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 in the defm name
+ std::string DefName = DefProto->getName();
+ std::string::size_type idx = DefName.find("#NAME#");
+ if (idx != std::string::npos) {
+ DefName.replace(idx, 6, DefmPrefix);
+ }
+ else {
+ // Add the suffix to the defm name to get the new name.
+ DefName = DefmPrefix + DefName;
+ }
+
+ Record *CurRec = new Record(DefName, DefmPrefixLoc);
+
+ SubClassReference Ref;
+ Ref.RefLoc = DefmPrefixLoc;
+ Ref.Rec = DefProto;
+ AddSubClass(CurRec, Ref);
+
+ // 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) {
+ // Check if a value is specified for this temp-arg.
+ if (i < TemplateVals.size()) {
+ // Set it now.
+ if (SetValue(CurRec, DefmPrefixLoc, TArgs[i], std::vector<unsigned>(),
+ TemplateVals[i]))
+ return true;
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[i]);
+
+ } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
+ return Error(SubClassLoc,
+ "value not specified for template argument #"+
+ utostr(i) + " (" + TArgs[i] + ") of multiclassclass '" +
+ MC->Rec.getName() + "'");
+ }
+ }
+
+ // 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)
+ if (SetValue(CurRec, LetStack[i][j].Loc, LetStack[i][j].Name,
+ LetStack[i][j].Bits, LetStack[i][j].Value)) {
+ Error(DefmPrefixLoc, "when instantiating this defm");
+ return true;
+ }
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName()))
+ return Error(DefmPrefixLoc, "def '" + CurRec->getName() +
+ "' already defined, instantiating defm with subdef '" +
+ DefProto->getName() + "'");
+ Records.addDef(CurRec);
+ CurRec->resolveReferences();
+ }
+
+ if (Lex.getCode() != tgtok::comma) break;
+ Lex.Lex(); // eat ','.
+
+ SubClassLoc = Lex.getLoc();
+ Ref = ParseSubClassReference(0, true);
+ }
+
+ if (Lex.getCode() != tgtok::semi)
+ return TokError("expected ';' at end of defm");
+ Lex.Lex();
+
+ return false;
+}
+
+/// ParseObject
+/// Object ::= ClassInst
+/// Object ::= DefInst
+/// Object ::= MultiClassInst
+/// Object ::= DefMInst
+/// Object ::= LETCommand '{' ObjectList '}'
+/// Object ::= LETCommand Object
+bool TGParser::ParseObject() {
+ switch (Lex.getCode()) {
+ default: assert(0 && "This is not an object");
+ case tgtok::Let: return ParseTopLevelLet();
+ case tgtok::Def: return ParseDef(0) == 0;
+ case tgtok::Defm: return ParseDefm();
+ case tgtok::Class: return ParseClass();
+ case tgtok::MultiClass: return ParseMultiClass();
+ }
+}
+
+/// ParseObjectList
+/// ObjectList :== Object*
+bool TGParser::ParseObjectList() {
+ while (isObjectStart(Lex.getCode())) {
+ if (ParseObject())
+ return true;
+ }
+ return false;
+}
+
+
+bool TGParser::ParseFile() {
+ Lex.Lex(); // Prime the lexer.
+ if (ParseObjectList()) return true;
+
+ // If we have unread input at the end of the file, report it.
+ if (Lex.getCode() == tgtok::Eof)
+ return false;
+
+ return TokError("Unexpected input at top level");
+}
+
diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h
new file mode 100644
index 000000000000..f03052eb7991
--- /dev/null
+++ b/utils/TableGen/TGParser.h
@@ -0,0 +1,115 @@
+//===- TGParser.h - Parser for TableGen Files -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class represents the Parser for tablegen files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TGPARSER_H
+#define TGPARSER_H
+
+#include "TGLexer.h"
+#include "TGSourceMgr.h"
+#include <map>
+
+namespace llvm {
+ class Record;
+ class RecordVal;
+ struct RecTy;
+ struct Init;
+ struct MultiClass;
+ struct SubClassReference;
+ struct SubMultiClassReference;
+
+ struct LetRecord {
+ std::string Name;
+ std::vector<unsigned> Bits;
+ Init *Value;
+ TGLoc Loc;
+ LetRecord(const std::string &N, const std::vector<unsigned> &B, Init *V,
+ TGLoc L)
+ : Name(N), Bits(B), Value(V), Loc(L) {
+ }
+ };
+
+class TGParser {
+ TGLexer Lex;
+ std::vector<std::vector<LetRecord> > LetStack;
+ std::map<std::string, MultiClass*> MultiClasses;
+
+ /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the
+ /// current value.
+ MultiClass *CurMultiClass;
+public:
+ TGParser(TGSourceMgr &SrcMgr) : Lex(SrcMgr), CurMultiClass(0) {}
+
+ void setIncludeDirs(const std::vector<std::string> &D){Lex.setIncludeDirs(D);}
+
+ /// ParseFile - Main entrypoint for parsing a tblgen file. These parser
+ /// routines return true on error, or false on success.
+ bool ParseFile();
+
+ bool Error(TGLoc L, const std::string &Msg) const {
+ Lex.PrintError(L, Msg);
+ return true;
+ }
+ bool TokError(const std::string &Msg) const {
+ return Error(Lex.getLoc(), Msg);
+ }
+private: // Semantic analysis methods.
+ bool AddValue(Record *TheRec, TGLoc Loc, const RecordVal &RV);
+ bool SetValue(Record *TheRec, TGLoc Loc, const std::string &ValName,
+ const std::vector<unsigned> &BitList, Init *V);
+ bool AddSubClass(Record *Rec, SubClassReference &SubClass);
+ bool AddSubMultiClass(MultiClass *CurMC,
+ SubMultiClassReference &SubMultiClass);
+
+private: // Parser methods.
+ bool ParseObjectList();
+ bool ParseObject();
+ bool ParseClass();
+ bool ParseMultiClass();
+ bool ParseMultiClassDef(MultiClass *CurMC);
+ bool ParseDefm();
+ bool ParseTopLevelLet();
+ std::vector<LetRecord> ParseLetList();
+
+ Record *ParseDef(MultiClass *CurMultiClass);
+ bool ParseObjectBody(Record *CurRec);
+ bool ParseBody(Record *CurRec);
+ bool ParseBodyItem(Record *CurRec);
+
+ bool ParseTemplateArgList(Record *CurRec);
+ std::string ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs);
+
+ SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm);
+ SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC);
+
+ Init *ParseIDValue(Record *CurRec);
+ Init *ParseIDValue(Record *CurRec, const std::string &Name, TGLoc NameLoc);
+ Init *ParseSimpleValue(Record *CurRec);
+ Init *ParseValue(Record *CurRec);
+ std::vector<Init*> ParseValueList(Record *CurRec);
+ std::vector<std::pair<llvm::Init*, std::string> > ParseDagArgList(Record *);
+ bool ParseOptionalRangeList(std::vector<unsigned> &Ranges);
+ bool ParseOptionalBitList(std::vector<unsigned> &Ranges);
+ std::vector<unsigned> ParseRangeList();
+ bool ParseRangePiece(std::vector<unsigned> &Ranges);
+ RecTy *ParseType();
+ Init *ParseOperation(Record *CurRec);
+ RecTy *ParseOperatorType();
+ std::string ParseObjectName();
+ Record *ParseClassID();
+ MultiClass *ParseMultiClassID();
+ Record *ParseDefmID();
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/utils/TableGen/TGSourceMgr.cpp b/utils/TableGen/TGSourceMgr.cpp
new file mode 100644
index 000000000000..42bc75246c9f
--- /dev/null
+++ b/utils/TableGen/TGSourceMgr.cpp
@@ -0,0 +1,105 @@
+//===- TGSourceMgr.cpp - Manager for Source Buffers & Diagnostics ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the TGSourceMgr class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TGSourceMgr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+TGSourceMgr::~TGSourceMgr() {
+ while (!Buffers.empty()) {
+ delete Buffers.back().Buffer;
+ Buffers.pop_back();
+ }
+}
+
+/// FindBufferContainingLoc - Return the ID of the buffer containing the
+/// specified location, returning -1 if not found.
+int TGSourceMgr::FindBufferContainingLoc(TGLoc Loc) const {
+ for (unsigned i = 0, e = Buffers.size(); i != e; ++i)
+ if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() &&
+ // Use <= here so that a pointer to the null at the end of the buffer
+ // is included as part of the buffer.
+ Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd())
+ return i;
+ return -1;
+}
+
+/// FindLineNumber - Find the line number for the specified location in the
+/// specified file. This is not a fast method.
+unsigned TGSourceMgr::FindLineNumber(TGLoc Loc, int BufferID) const {
+ if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc);
+ assert(BufferID != -1 && "Invalid Location!");
+
+ MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer;
+
+ // Count the number of \n's between the start of the file and the specified
+ // location.
+ unsigned LineNo = 1;
+
+ const char *Ptr = Buff->getBufferStart();
+
+ for (; TGLoc::getFromPointer(Ptr) != Loc; ++Ptr)
+ if (*Ptr == '\n') ++LineNo;
+ return LineNo;
+}
+
+void TGSourceMgr::PrintIncludeStack(TGLoc IncludeLoc) const {
+ if (IncludeLoc == TGLoc()) return; // Top of stack.
+
+ int CurBuf = FindBufferContainingLoc(IncludeLoc);
+ assert(CurBuf != -1 && "Invalid or unspecified location!");
+
+ PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc);
+
+ errs() << "Included from "
+ << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
+ << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
+}
+
+
+void TGSourceMgr::PrintError(TGLoc ErrorLoc, const std::string &Msg) const {
+ raw_ostream &OS = errs();
+
+ // First thing to do: find the current buffer containing the specified
+ // location.
+ int CurBuf = FindBufferContainingLoc(ErrorLoc);
+ assert(CurBuf != -1 && "Invalid or unspecified location!");
+
+ PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc);
+
+ MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer;
+
+
+ OS << "Parsing " << CurMB->getBufferIdentifier() << ":"
+ << FindLineNumber(ErrorLoc, CurBuf) << ": ";
+
+ OS << Msg << "\n";
+
+ // Scan backward to find the start of the line.
+ const char *LineStart = ErrorLoc.getPointer();
+ while (LineStart != CurMB->getBufferStart() &&
+ LineStart[-1] != '\n' && LineStart[-1] != '\r')
+ --LineStart;
+ // Get the end of the line.
+ const char *LineEnd = ErrorLoc.getPointer();
+ while (LineEnd != CurMB->getBufferEnd() &&
+ LineEnd[0] != '\n' && LineEnd[0] != '\r')
+ ++LineEnd;
+ // Print out the line.
+ OS << std::string(LineStart, LineEnd) << "\n";
+ // Print out spaces before the caret.
+ for (const char *Pos = LineStart; Pos != ErrorLoc.getPointer(); ++Pos)
+ OS << (*Pos == '\t' ? '\t' : ' ');
+ OS << "^\n";
+}
diff --git a/utils/TableGen/TGSourceMgr.h b/utils/TableGen/TGSourceMgr.h
new file mode 100644
index 000000000000..69fb74ca20c6
--- /dev/null
+++ b/utils/TableGen/TGSourceMgr.h
@@ -0,0 +1,106 @@
+//===- TGSourceMgr.h - Manager for Source Buffers & Diagnostics -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the TGSourceMgr class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TGSOURCEMGR_H
+#define TGSOURCEMGR_H
+
+#include <string>
+#include <vector>
+#include <cassert>
+
+namespace llvm {
+ class MemoryBuffer;
+ class TGSourceMgr;
+
+class TGLoc {
+ const char *Ptr;
+public:
+ TGLoc() : Ptr(0) {}
+ TGLoc(const TGLoc &RHS) : Ptr(RHS.Ptr) {}
+
+ bool operator==(const TGLoc &RHS) const { return RHS.Ptr == Ptr; }
+ bool operator!=(const TGLoc &RHS) const { return RHS.Ptr != Ptr; }
+
+ const char *getPointer() const { return Ptr; }
+
+ static TGLoc getFromPointer(const char *Ptr) {
+ TGLoc L;
+ L.Ptr = Ptr;
+ return L;
+ }
+};
+
+/// TGSourceMgr - This owns the files read by tblgen, handles include stacks,
+/// and handles printing of diagnostics.
+class TGSourceMgr {
+ struct SrcBuffer {
+ /// Buffer - The memory buffer for the file.
+ MemoryBuffer *Buffer;
+
+ /// IncludeLoc - This is the location of the parent include, or null if at
+ /// the top level.
+ TGLoc IncludeLoc;
+ };
+
+ /// Buffers - This is all of the buffers that we are reading from.
+ std::vector<SrcBuffer> Buffers;
+
+ TGSourceMgr(const TGSourceMgr&); // DO NOT IMPLEMENT
+ void operator=(const TGSourceMgr&); // DO NOT IMPLEMENT
+public:
+ TGSourceMgr() {}
+ ~TGSourceMgr();
+
+ const SrcBuffer &getBufferInfo(unsigned i) const {
+ assert(i < Buffers.size() && "Invalid Buffer ID!");
+ return Buffers[i];
+ }
+
+ const MemoryBuffer *getMemoryBuffer(unsigned i) const {
+ assert(i < Buffers.size() && "Invalid Buffer ID!");
+ return Buffers[i].Buffer;
+ }
+
+ TGLoc getParentIncludeLoc(unsigned i) const {
+ assert(i < Buffers.size() && "Invalid Buffer ID!");
+ return Buffers[i].IncludeLoc;
+ }
+
+ unsigned AddNewSourceBuffer(MemoryBuffer *F, TGLoc IncludeLoc) {
+ SrcBuffer NB;
+ NB.Buffer = F;
+ NB.IncludeLoc = IncludeLoc;
+ Buffers.push_back(NB);
+ return Buffers.size()-1;
+ }
+
+ /// FindBufferContainingLoc - Return the ID of the buffer containing the
+ /// specified location, returning -1 if not found.
+ int FindBufferContainingLoc(TGLoc Loc) const;
+
+ /// FindLineNumber - Find the line number for the specified location in the
+ /// specified file. This is not a fast method.
+ unsigned FindLineNumber(TGLoc Loc, int BufferID = -1) const;
+
+
+ /// PrintError - Emit an error message about the specified location with the
+ /// specified string.
+ void PrintError(TGLoc ErrorLoc, const std::string &Msg) const;
+
+private:
+ void PrintIncludeStack(TGLoc IncludeLoc) const;
+};
+
+} // end llvm namespace
+
+#endif
diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp
new file mode 100644
index 000000000000..8979e13f72ba
--- /dev/null
+++ b/utils/TableGen/TGValueTypes.cpp
@@ -0,0 +1,126 @@
+//===- ValueTypes.cpp - Tablegen extended ValueType implementation --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The MVT type is used by tablegen as well as in LLVM. In order to handle
+// extended types, the MVT type uses support functions that call into
+// LLVM's type system code. These aren't accessible in tablegen, so this
+// file provides simple replacements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/Support/Streams.h"
+#include <map>
+#include <vector>
+using namespace llvm;
+
+namespace llvm {
+
+class Type {
+public:
+ virtual unsigned getSizeInBits() const = 0;
+ virtual ~Type() {}
+};
+
+}
+
+class ExtendedIntegerType : public Type {
+ unsigned BitWidth;
+public:
+ explicit ExtendedIntegerType(unsigned bits)
+ : BitWidth(bits) {}
+ unsigned getSizeInBits() const {
+ return getBitWidth();
+ }
+ unsigned getBitWidth() const {
+ return BitWidth;
+ }
+};
+
+class ExtendedVectorType : public Type {
+ MVT ElementType;
+ unsigned NumElements;
+public:
+ ExtendedVectorType(MVT elty, unsigned num)
+ : ElementType(elty), NumElements(num) {}
+ unsigned getSizeInBits() const {
+ return getNumElements() * getElementType().getSizeInBits();
+ }
+ MVT getElementType() const {
+ return ElementType;
+ }
+ unsigned getNumElements() const {
+ return NumElements;
+ }
+};
+
+static std::map<unsigned, const Type *>
+ ExtendedIntegerTypeMap;
+static std::map<std::pair<uintptr_t, uintptr_t>, const Type *>
+ ExtendedVectorTypeMap;
+
+MVT MVT::getExtendedIntegerVT(unsigned BitWidth) {
+ const Type *&ET = ExtendedIntegerTypeMap[BitWidth];
+ if (!ET) ET = new ExtendedIntegerType(BitWidth);
+ MVT VT;
+ VT.LLVMTy = ET;
+ assert(VT.isExtended() && "Type is not extended!");
+ return VT;
+}
+
+MVT MVT::getExtendedVectorVT(MVT VT, unsigned NumElements) {
+ const Type *&ET = ExtendedVectorTypeMap[std::make_pair(VT.getRawBits(),
+ NumElements)];
+ if (!ET) ET = new ExtendedVectorType(VT, NumElements);
+ MVT ResultVT;
+ ResultVT.LLVMTy = ET;
+ assert(ResultVT.isExtended() && "Type is not extended!");
+ return ResultVT;
+}
+
+bool MVT::isExtendedFloatingPoint() const {
+ assert(isExtended() && "Type is not extended!");
+ // Extended floating-point types are not supported yet.
+ return false;
+}
+
+bool MVT::isExtendedInteger() const {
+ assert(isExtended() && "Type is not extended!");
+ return dynamic_cast<const ExtendedIntegerType *>(LLVMTy) != 0;
+}
+
+bool MVT::isExtendedVector() const {
+ assert(isExtended() && "Type is not extended!");
+ return dynamic_cast<const ExtendedVectorType *>(LLVMTy) != 0;
+}
+
+bool MVT::isExtended64BitVector() const {
+ assert(isExtended() && "Type is not extended!");
+ return isExtendedVector() && getSizeInBits() == 64;
+}
+
+bool MVT::isExtended128BitVector() const {
+ assert(isExtended() && "Type is not extended!");
+ return isExtendedVector() && getSizeInBits() == 128;
+}
+
+MVT MVT::getExtendedVectorElementType() const {
+ assert(isExtendedVector() && "Type is not an extended vector!");
+ return static_cast<const ExtendedVectorType *>(LLVMTy)->getElementType();
+}
+
+unsigned MVT::getExtendedVectorNumElements() const {
+ assert(isExtendedVector() && "Type is not an extended vector!");
+ return static_cast<const ExtendedVectorType *>(LLVMTy)->getNumElements();
+}
+
+unsigned MVT::getExtendedSizeInBits() const {
+ assert(isExtended() && "Type is not extended!");
+ return LLVMTy->getSizeInBits();
+}
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
new file mode 100644
index 000000000000..dbc4d33e816b
--- /dev/null
+++ b/utils/TableGen/TableGen.cpp
@@ -0,0 +1,270 @@
+//===- TableGen.cpp - Top-Level TableGen implementation -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 "TGParser.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/System/Signals.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "CallingConvEmitter.h"
+#include "CodeEmitterGen.h"
+#include "RegisterInfoEmitter.h"
+#include "InstrInfoEmitter.h"
+#include "InstrEnumEmitter.h"
+#include "AsmWriterEmitter.h"
+#include "DAGISelEmitter.h"
+#include "FastISelEmitter.h"
+#include "SubtargetEmitter.h"
+#include "IntrinsicEmitter.h"
+#include "LLVMCConfigurationEmitter.h"
+#include "ClangDiagnosticsEmitter.h"
+#include <algorithm>
+#include <cstdio>
+#include <fstream>
+#include <ios>
+using namespace llvm;
+
+enum ActionType {
+ PrintRecords,
+ GenEmitter,
+ GenRegisterEnums, GenRegister, GenRegisterHeader,
+ GenInstrEnums, GenInstrs, GenAsmWriter,
+ GenCallingConv,
+ GenClangDiagsDefs,
+ GenClangDiagGroups,
+ GenDAGISel,
+ GenFastISel,
+ GenSubtarget,
+ GenIntrinsic,
+ GenTgtIntrinsic,
+ GenLLVMCConf,
+ 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(GenFastISel, "gen-fast-isel",
+ "Generate a \"fast\" instruction selector"),
+ clEnumValN(GenSubtarget, "gen-subtarget",
+ "Generate subtarget enumerations"),
+ clEnumValN(GenIntrinsic, "gen-intrinsic",
+ "Generate intrinsic information"),
+ clEnumValN(GenTgtIntrinsic, "gen-tgt-intrinsic",
+ "Generate target intrinsic information"),
+ clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
+ "Generate Clang diagnostics definitions"),
+ clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
+ "Generate Clang diagnostic groups"),
+ clEnumValN(GenLLVMCConf, "gen-llvmc",
+ "Generate LLVMC configuration library"),
+ 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);
+
+ cl::opt<std::string>
+ ClangComponent("clang-component",
+ cl::desc("Only use warnings from specified component"),
+ cl::value_desc("component"), cl::Hidden);
+}
+
+
+// FIXME: Eliminate globals from tblgen.
+RecordKeeper llvm::Records;
+
+static TGSourceMgr SrcMgr;
+
+void llvm::PrintError(TGLoc ErrorLoc, const std::string &Msg) {
+ SrcMgr.PrintError(ErrorLoc, Msg);
+}
+
+
+
+/// ParseFile - this function begins the parsing of the specified tablegen
+/// file.
+static bool ParseFile(const std::string &Filename,
+ const std::vector<std::string> &IncludeDirs,
+ TGSourceMgr &SrcMgr) {
+ std::string ErrorStr;
+ MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr);
+ if (F == 0) {
+ cerr << "Could not open input file '" + Filename + "': " << ErrorStr <<"\n";
+ return true;
+ }
+
+ // Tell SrcMgr about this buffer, which is what TGParser will pick up.
+ SrcMgr.AddNewSourceBuffer(F, TGLoc());
+
+ TGParser Parser(SrcMgr);
+
+ // Record the location of the include directory so that the lexer can find
+ // it later.
+ Parser.setIncludeDirs(IncludeDirs);
+
+ return Parser.ParseFile();
+}
+
+int main(int argc, char **argv) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv);
+
+
+ // Parse the input file.
+ if (ParseFile(InputFilename, IncludeDirs, SrcMgr))
+ return 1;
+
+ 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:
+ InstrEnumEmitter(Records).run(*Out);
+ break;
+ case GenInstrs:
+ InstrInfoEmitter(Records).run(*Out);
+ break;
+ case GenCallingConv:
+ CallingConvEmitter(Records).run(*Out);
+ break;
+ case GenAsmWriter:
+ AsmWriterEmitter(Records).run(*Out);
+ break;
+ case GenClangDiagsDefs:
+ ClangDiagsDefsEmitter(Records, ClangComponent).run(*Out);
+ break;
+ case GenClangDiagGroups:
+ ClangDiagGroupsEmitter(Records).run(*Out);
+ break;
+ case GenDAGISel:
+ DAGISelEmitter(Records).run(*Out);
+ break;
+ case GenFastISel:
+ FastISelEmitter(Records).run(*Out);
+ break;
+ case GenSubtarget:
+ SubtargetEmitter(Records).run(*Out);
+ break;
+ case GenIntrinsic:
+ IntrinsicEmitter(Records).run(*Out);
+ break;
+ case GenTgtIntrinsic:
+ IntrinsicEmitter(Records, true).run(*Out);
+ break;
+ case GenLLVMCConf:
+ LLVMCConfigurationEmitter(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;
+ }
+
+ if (Out != cout.stream())
+ delete Out; // Close the file
+ return 0;
+
+ } catch (const TGError &Error) {
+ cerr << argv[0] << ": error:\n";
+ PrintError(Error.getLoc(), Error.getMessage());
+
+ } catch (const std::string &Error) {
+ cerr << argv[0] << ": " << Error << "\n";
+ } catch (const char *Error) {
+ cerr << argv[0] << ": " << Error << "\n";
+ } 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 1;
+}
diff --git a/utils/TableGen/TableGenBackend.cpp b/utils/TableGen/TableGenBackend.cpp
new file mode 100644
index 000000000000..87a1b3da1196
--- /dev/null
+++ b/utils/TableGen/TableGenBackend.cpp
@@ -0,0 +1,25 @@
+//===- TableGenBackend.cpp - Base class for TableGen Backends ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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";
+}
+
diff --git a/utils/TableGen/TableGenBackend.h b/utils/TableGen/TableGenBackend.h
new file mode 100644
index 000000000000..109bc9f9ae8d
--- /dev/null
+++ b/utils/TableGen/TableGenBackend.h
@@ -0,0 +1,43 @@
+//===- TableGenBackend.h - Base class for TableGen Backends -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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;
+
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/buildit/GNUmakefile b/utils/buildit/GNUmakefile
new file mode 100644
index 000000000000..6e5131254cb0
--- /dev/null
+++ b/utils/buildit/GNUmakefile
@@ -0,0 +1,115 @@
+# LLVM LOCAL file build machinery
+# LLVM Compiler Makefile for use by buildit.
+#
+# This makefile is intended only for use with B&I buildit. For "normal" builds
+# use the conventional top-level makefile.
+#
+# You can specify TARGETS=ppc (or i386) on the buildit command line to limit the
+# build to just one target. The default is for ppc and i386. The compiler
+# targetted at this host gets built anyway, but not installed unless it's listed
+# in TARGETS.
+
+# Include the set of standard Apple makefile definitions.
+ifndef CoreOSMakefiles
+CoreOSMakefiles = $(MAKEFILEPATH)/CoreOS
+endif
+include $(CoreOSMakefiles)/Standard/Standard.make
+
+# Enable Apple extensions to (gnu)make.
+USE_APPLE_PB_SUPPORT = all
+
+RC_ARCHS := ppc i386
+HOSTS = $(RC_ARCHS)
+targets = echo $(RC_ARCHS)
+TARGETS := $(shell $(targets))
+
+SRCROOT = .
+
+SRC = $(shell cd $(SRCROOT) && pwd | sed s,/private,,)
+OBJROOT = $(SRC)/obj
+SYMROOT = $(OBJROOT)/../sym
+DSTROOT = $(OBJROOT)/../dst
+
+#######################################################################
+
+PREFIX = /usr/local
+
+# Unless assertions are forced on in the GMAKE command line, disable them.
+ifdef ENABLE_ASSERTIONS
+LLVM_ASSERTIONS := yes
+else
+LLVM_ASSERTIONS := no
+endif
+
+# Default is optimized build.
+ifeq ($(LLVM_DEBUG),1)
+LLVM_OPTIMIZED := no
+else
+LLVM_OPTIMIZED := yes
+endif
+
+ifndef RC_ProjectSourceVersion
+RC_ProjectSourceVersion = 9999
+endif
+
+ifndef RC_ProjectSourceSubversion
+RC_ProjectSourceSubversion = 0
+endif
+
+# NOTE : Always put version numbers at the end because they are optional.
+install: $(OBJROOT) $(SYMROOT) $(DSTROOT)
+ cd $(OBJROOT) && \
+ $(SRC)/build_llvm "$(RC_ARCHS)" "$(TARGETS)" \
+ $(SRC) $(PREFIX) $(DSTROOT) $(SYMROOT) \
+ $(LLVM_ASSERTIONS) $(LLVM_OPTIMIZED) \
+ $(RC_ProjectSourceVersion) $(RC_ProjectSourceSubversion)
+
+
+# installhdrs does nothing, because the headers aren't useful until
+# the compiler is installed.
+installhdrs:
+
+# We build and install in one shell script.
+build:
+
+installsrc:
+ @echo
+ @echo ++++++++++++++++++++++
+ @echo + Installing sources +
+ @echo ++++++++++++++++++++++
+ @echo
+ if [ $(SRCROOT) != . ]; then \
+ $(PAX) -rw . $(SRCROOT); \
+ fi
+ find -d "$(SRCROOT)" \( -type d -a -name .svn -o \
+ -type f -a -name .DS_Store -o \
+ -name \*~ -o -name .\#\* \) \
+ -exec rm -rf {} \;
+
+#######################################################################
+
+clean:
+ @echo
+ @echo ++++++++++++
+ @echo + Cleaning +
+ @echo ++++++++++++
+ @echo
+ @if [ -d $(OBJROOT) -a "$(OBJROOT)" != / ]; then \
+ echo '*** DELETING ' $(OBJROOT); \
+ rm -rf $(OBJROOT); \
+ fi
+ @if [ -d $(SYMROOT) -a "$(SYMROOT)" != / ]; then \
+ echo '*** DELETING ' $(SYMROOT); \
+ rm -rf $(SYMROOT); \
+ fi
+ @if [ -d $(DSTROOT) -a "$(DSTROOT)" != / ]; then \
+ echo '*** DELETING ' $(DSTROOT); \
+ rm -rf $(DSTROOT); \
+ fi
+
+#######################################################################
+
+$(OBJROOT) $(SYMROOT) $(DSTROOT):
+ mkdir -p $@
+
+.PHONY: install installsrc clean
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
new file mode 100755
index 000000000000..eac68b4f572f
--- /dev/null
+++ b/utils/buildit/build_llvm
@@ -0,0 +1,272 @@
+#!/bin/sh
+# LLVM LOCAL file B&I
+
+set -x
+
+# Build LLVM the "Apple way".
+# Parameters:
+
+# The first parameter is a space-separated list of the architectures the
+# compilers will run on. For instance, "ppc i386". If the current machine
+# isn't in the list, it will (effectively) be added.
+# FIXME: HOSTS is not used in this script. Use it or Remove it.
+HOSTS="$1"
+
+# The second parameter is a space-separated list of the architectures the
+# compilers will generate code for. If the current machine isn't in the list, a
+# compiler for it will get built anyway, but won't be installed.
+TARGETS="$2"
+
+# The third parameter is the path to the compiler sources. There should be a
+# shell script named 'configure' in this directory. This script makes a copy...
+ORIG_SRC_DIR="$3"
+
+# The fourth parameter is the location where the LLVM will be installed. You can
+# move it once it's built, so this mostly controls the layout of $DEST_DIR.
+DEST_ROOT="$4"
+
+# The fifth parameter is the place where the compiler will be copied once it's
+# built.
+DEST_DIR="$5"
+
+# The sixth parameter is a directory in which to place information (like
+# unstripped executables and generated source files) helpful in debugging the
+# resulting compiler.
+SYM_DIR="$6"
+
+# The seventh parameter is a yes/no that indicates whether assertions should be
+# enabled in the LLVM libs/tools.
+LLVM_ASSERTIONS="$7"
+
+# The eighth parameter is a yes/no that indicates whether this is an optimized
+# build.
+LLVM_OPTIMIZED="$8"
+
+# The nineth parameter is the version number of the submission, e.g. 1007.
+LLVM_SUBMIT_VERSION="$9"
+
+# The tenth parameter is the subversion number of the submission, e.g. 03.
+LLVM_SUBMIT_SUBVERSION="${10}"
+
+# The current working directory is where the build will happen. It may already
+# contain a partial result of an interrupted build, in which case this script
+# will continue where it left off.
+DIR=`pwd`
+
+DARWIN_VERS=`uname -r | sed 's/\..*//'`
+echo DARWIN_VERS = $DARWIN_VERS
+
+# If the user has CC set in their environment unset it now
+unset CC
+
+DT_HOME=$DEST_DIR/Developer/usr
+DEST_ROOT="/Developer$DEST_ROOT"
+if [ "x$DEVELOPER_BIN" != "x" ]; then
+ DT_HOME=$DEST_DIR/$DEVELOPER_DIR/usr
+ DEST_ROOT="/$DEVELOPER_DIR$DEST_ROOT"
+fi
+
+################################################################################
+# Run the build.
+
+# Create the source tree we'll actually use to build, deleting
+# tcl since it doesn't actually build properly in a cross environment
+# and we don't really need it.
+SRC_DIR=$DIR/src
+rm -rf $SRC_DIR || exit 1
+mkdir $SRC_DIR || exit 1
+ln -s $ORIG_SRC_DIR/* $SRC_DIR/ || exit 1
+
+# Build the LLVM tree universal.
+mkdir -p $DIR/obj-llvm || exit 1
+cd $DIR/obj-llvm || exit 1
+
+if [ \! -f Makefile.config ]; then
+ $SRC_DIR/configure --prefix=$DT_HOME/local \
+ --enable-targets=arm,x86,powerpc,cbe \
+ --enable-assertions=$LLVM_ASSERTIONS \
+ --enable-optimized=$LLVM_OPTIMIZED \
+ || exit 1
+fi
+
+SUBVERSION=`echo $RC_ProjectSourceVersion | sed -e 's/[^.]*\.\([0-9]*\).*/\1/'`
+
+if [ "x$SUBVERSION" != "x$RC_ProjectSourceVersion" ]; then
+ LLVM_SUBMIT_SUBVERSION=`printf "%02d" $SUBVERSION`
+ RC_ProjectSourceVersion=`echo $RC_ProjectSourceVersion | sed -e 's/\..*//'`
+ LLVM_SUBMIT_VERSION=$RC_ProjectSourceVersion
+fi
+
+if [ "x$LLVM_SUBMIT_SUBVERSION" = "x00" -o "x$LLVM_SUBMIT_SUBVERSION" = "x0" ]; then
+ LLVM_VERSION="$LLVM_SUBMIT_VERSION"
+else
+ LLVM_VERSION="$LLVM_SUBMIT_VERSION-$LLVM_SUBMIT_SUBVERSION"
+fi
+
+GCC_VER=`cc --version 2>/dev/null | sed 1q`
+
+if echo "$GCC_VER" | grep GCC > /dev/null; then
+ GCC_VER=`echo $GCC_VER | sed -e 's/.*(GCC) \([0-9.][0-9.]*\).*/\1/'`
+ MAJ_VER=`echo $GCC_VER | sed 's/\..*//'`
+ MIN_VER=`echo $GCC_VER | sed 's/[^.]*\.\([0-9]*\).*/\1/'`
+fi
+
+JOBS_FLAG=""
+
+# Note: If compiling with GCC 4.0, don't pass the -jN flag. Building universal
+# already has parallelism and we don't want to make the builders hit swap by
+# firing off too many gccs at the same time.
+if [ "x$MAJ_VER" != "x4" -o "x$MIN_VER" != "x0" ]; then
+ # Figure out how many make processes to run.
+ SYSCTL=`sysctl -n hw.activecpu`
+
+ # hw.activecpu only available in 10.2.6 and later
+ if [ -z "$SYSCTL" ]; then
+ SYSCTL=`sysctl -n hw.ncpu`
+ fi
+
+ # sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot.
+ # Builders can default to 2, since even if they are single processor,
+ # nothing else is running on the machine.
+ if [ -z "$SYSCTL" ]; then
+ SYSCTL=2
+ fi
+
+ JOBS_FLAG="-j $SYSCTL"
+fi
+
+make $JOBS_FLAG $OPTIMIZE_OPTS UNIVERSAL=1 UNIVERSAL_ARCH="$TARGETS" \
+ LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
+ LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
+ CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'" \
+ VERBOSE=1
+
+if ! test $? == 0 ; then
+ echo "error: LLVM 'make' failed!"
+ exit 1
+fi
+
+################################################################################
+# Construct the actual destination root, by copying stuff from $DIR/dst-* to
+# $DEST_DIR, with occasional 'lipo' commands.
+
+cd $DEST_DIR || exit 1
+
+# Clean out DEST_DIR in case -noclean was passed to buildit.
+rm -rf * || exit 1
+
+cd $DIR/obj-llvm || exit 1
+
+# Install the tree into the destination directory.
+make $LOCAL_MAKEFLAGS $OPTIMIZE_OPTS UNIVERSAL=1 UNIVERSAL_ARCH="$TARGETS" \
+ LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
+ LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
+ OPTIMIZE_OPTION='-O3' VERBOSE=1 install
+
+if ! test $? == 0 ; then
+ echo "error: LLVM 'make install' failed!"
+ exit 1
+fi
+
+# Install Version.h
+RC_ProjectSourceSubversion=`printf "%d" $LLVM_SUBMIT_SUBVERSION`
+echo "#define LLVM_VERSION ${RC_ProjectSourceVersion}" > $DEST_DIR$DEST_ROOT/include/llvm/Version.h
+echo "#define LLVM_MINOR_VERSION ${RC_ProjectSourceSubversion}" >> $DEST_DIR$DEST_ROOT/include/llvm/Version.h
+
+if [ "x$LLVM_DEBUG" != "x1" ]; then
+ # Strip local symbols from llvm libraries.
+ strip -S $DEST_DIR$DEST_ROOT/lib/*.[oa]
+ for f in `ls $DEST_DIR$DEST_ROOT/lib/*.so`; do
+ strip -Sx $f
+ done
+fi
+
+# Copy over the tblgen utility.
+cp `find $DIR -name tblgen` $DT_HOME/local/bin
+
+# Remove .dir files
+cd $DEST_DIR$DEST_ROOT
+rm -f bin/.dir etc/llvm/.dir lib/.dir
+
+# Remove PPC64 fat slices.
+cd $DEST_DIR$DEST_ROOT/bin
+if [ $MACOSX_DEPLOYMENT_TARGET = "10.4" ]; then
+ find . -perm 755 -type f \! \( -name '*gccas' -o -name '*gccld' -o -name llvm-config \) \
+ -exec lipo -extract ppc -extract i386 {} -output {} \;
+elif [ $MACOSX_DEPLOYMENT_TARGET = "10.5" ]; then
+ find . -perm 755 -type f \! \( -name '*gccas' -o -name '*gccld' -o -name llvm-config \) \
+ -exec lipo -extract ppc7400 -extract i386 {} -output {} \;
+else
+ find . -perm 755 -type f \! \( -name '*gccas' -o -name '*gccld' -o -name llvm-config \) \
+ -exec lipo -extract ppc7400 -extract i386 -extract x86_64 {} -output {} \;
+fi
+
+cd $DEST_DIR$DEST_ROOT
+mkdir -p $DT_HOME/lib
+mv lib/libLTO.dylib $DT_HOME/lib/libLTO.dylib
+strip -S $DT_HOME/lib/libLTO.dylib
+rm -f lib/libLTO.a lib/libLTO.la
+
+# The Hello dylib is an example of how to build a pass. No need to install it.
+rm lib/libLLVMHello.dylib
+
+# Compress manpages
+MDIR=$DEST_DIR$DEST_ROOT/share/man/man1
+gzip -f $MDIR/*
+
+################################################################################
+# Create SYM_DIR with information required for debugging.
+
+# Figure out how many make processes to run.
+SYSCTL=`sysctl -n hw.activecpu`
+
+# hw.activecpu only available in 10.2.6 and later
+if [ -z "$SYSCTL" ]; then
+ SYSCTL=`sysctl -n hw.ncpu`
+fi
+
+# sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot. Builders
+# can default to 2, since even if they are single processor, nothing else is
+# running on the machine.
+if [ -z "$SYSCTL" ]; then
+ SYSCTL=2
+fi
+
+cd $SYM_DIR || exit 1
+
+# Clean out SYM_DIR in case -noclean was passed to buildit.
+rm -rf * || exit 1
+
+# Generate .dSYM files
+find $DEST_DIR -perm -0111 -type f \
+ ! \( -name '*.la' -o -name gccas -o -name gccld -o -name llvm-config -o -name '*.a' \) \
+ -print | xargs -n 1 -P ${SYSCTL} dsymutil
+
+# Save .dSYM files and .a archives
+cd $DEST_DIR || exit 1
+find . \( -path \*.dSYM/\* -or -name \*.a \) -print \
+ | cpio -pdml $SYM_DIR || exit 1
+
+# Save source files.
+mkdir $SYM_DIR/src || exit 1
+cd $DIR || exit 1
+find obj-* -name \*.\[chy\] -o -name \*.cpp -print \
+ | cpio -pdml $SYM_DIR/src || exit 1
+
+################################################################################
+# Remove debugging information from DEST_DIR.
+
+find $DEST_DIR -name \*.a -print | xargs ranlib || exit 1
+find $DEST_DIR -name \*.dSYM -print | xargs rm -r || exit 1
+chgrp -h -R wheel $DEST_DIR
+chgrp -R wheel $DEST_DIR
+
+################################################################################
+# Remove tar ball from docs directory
+
+find $DEST_DIR -name html.tar.gz -exec rm {} \;
+
+################################################################################
+# w00t! Done!
+
+exit 0
diff --git a/utils/cgiplotNLT.pl b/utils/cgiplotNLT.pl
new file mode 100755
index 000000000000..0360e4120d8c
--- /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 000000000000..bd7633301dc2
--- /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 000000000000..2c3ac4c6dfa8
--- /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 000000000000..4d1b775d74aa
--- /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 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 000000000000..e83eeae4b070
--- /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 000000000000..a12848b45754
--- /dev/null
+++ b/utils/emacs/emacs.el
@@ -0,0 +1,36 @@
+;; 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))
+
+
+;; Alternative to setting the global style. Only files with "llvm" in
+;; their names will automatically set to the llvm.org coding style.
+(c-add-style "llvm.org"
+ '((fill-column . 80)
+ (c++-indent-level . 2)
+ (c-basic-offset . 2)
+ (indent-tabs-mode . nil)))
+(add-hook 'c-mode-hook
+ (function
+ (lambda nil
+ (if (string-match "llvm" buffer-file-name)
+ (progn
+ (c-set-style "llvm.org")
+ )
+ ))))
+(add-hook 'c++-mode-hook
+ (function
+ (lambda nil
+ (if (string-match "llvm" buffer-file-name)
+ (progn
+ (c-set-style "llvm.org")
+ )
+ ))))
diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el
new file mode 100644
index 000000000000..55c56daecd05
--- /dev/null
+++ b/utils/emacs/llvm-mode.el
@@ -0,0 +1,128 @@
+;; Maintainer: The LLVM team, http://llvm.org/
+;; Description: Major mode for the LLVM assembler language.
+;; Updated: 2007-09-19
+
+;; 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)
+ ;; Types
+ '("\\bvoid\\b\\|\\bi[0-9]+\\b\\|\\float\\b\\|\\bdouble\\b\\|\\btype\\b\\|\\blabel\\b\\|\\bopaque\\b" . font-lock-type-face)
+ ;; Integer literals
+ '("\\b[-]?[0-9]+\\b" . font-lock-preprocessor-face)
+ ;; Floating point constants
+ '("\\b[-+]?[0-9]+\.[0-9]*\([eE][-+]?[0-9]+\)?\\b" . font-lock-preprocessor-face)
+ ;; Hex constants
+ '("\\b0x[0-9A-Fa-f]+\\b" . font-lock-preprocessor-face)
+ ;; Keywords
+ '("\\bbegin\\b\\|\\bend\\b\\|\\btrue\\b\\|\\bfalse\\b\\|\\bzeroinitializer\\b\\|\\bdeclare\\b\\|\\bdefine\\b\\|\\bglobal\\b\\|\\bconstant\\b\\|\\bconst\\b\\|\\binternal\\b\\|\\blinkonce\\b\\|\\blinkonce_odr\\b\\|\\bweak\\b\\|\\bweak_odr\\b\\|\\bappending\\b\\|\\buninitialized\\b\\|\\bimplementation\\b\\|\\b\\.\\.\\.\\b\\|\\bnull\\b\\|\\bundef\\b\\|\\bto\\b\\|\\bexcept\\b\\|\\bnot\\b\\|\\btarget\\b\\|\\bendian\\b\\|\\blittle\\b\\|\\bbig\\b\\|\\bpointersize\\b\\|\\bdeplibs\\b\\|\\bvolatile\\b\\|\\bfastcc\\b\\|\\bcoldcc\\b\\|\\bcc\\b" . font-lock-keyword-face)
+ ;; Arithmetic and Logical Operators
+ '("\\badd\\b\\|\\bsub\\b\\|\\bmul\\b\\|\\bdiv\\b\\|\\brem\\b\\|\\band\\b\\|\\bor\\b\\|\\bxor\\b\\|\\bset\\(ne\\b\\|\\beq\\b\\|\\blt\\b\\|\\bgt\\b\\|\\ble\\b\\|\\bge\\b\\)" . font-lock-keyword-face)
+ ;; Special instructions
+ '("\\bphi\\b\\|\\btail\\b\\|\\bcall\\b\\|\\bcast\\b\\|\\bselect\\b\\|\\bto\\b\\|\\bshl\\b\\|\\bshr\\b\\|\\bvaarg\\b\\|\\bvanext\\b" . font-lock-keyword-face)
+ ;; Control instructions
+ '("\\bret\\b\\|\\bbr\\b\\|\\bswitch\\b\\|\\binvoke\\b\\|\\bunwind\\b\\|\\bunreachable\\b" . font-lock-keyword-face)
+ ;; Memory operators
+ '("\\bmalloc\\b\\|\\balloca\\b\\|\\bfree\\b\\|\\bload\\b\\|\\bstore\\b\\|\\bgetelementptr\\b" . 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)
+ (setq comment-start ";")
+ (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 000000000000..08f7f252c681
--- /dev/null
+++ b/utils/emacs/tablegen-mode.el
@@ -0,0 +1,122 @@
+;; Maintainer: The LLVM team, http://llvm.org/
+;; Description: Major mode for TableGen description files (part of LLVM project)
+;; Updated: 2007-12-18
+
+(require 'comint)
+(require 'custom)
+(require 'ansi-color)
+
+;; Create mode-specific tables.
+(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" "defm" "def" "field" "include" "in"
+ "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
+
+(defvar tablegen-mode-syntax-table nil
+ "Syntax table used in `tablegen-mode' buffers.")
+(when (not tablegen-mode-syntax-table)
+ (setq tablegen-mode-syntax-table (make-syntax-table))
+ ;; whitespace (` ')
+ (modify-syntax-entry ?\ " " tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\t " " tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\r " " tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\n " " tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\f " " tablegen-mode-syntax-table)
+ ;; word constituents (`w')
+ (modify-syntax-entry ?\% "w" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\_ "w" tablegen-mode-syntax-table)
+ ;; comments
+ (modify-syntax-entry ?/ ". 124b" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?* ". 23" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\n "> b" tablegen-mode-syntax-table)
+ ;; open paren (`(')
+ (modify-syntax-entry ?\( "(" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\[ "(" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\{ "(" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\< "(" tablegen-mode-syntax-table)
+ ;; close paren (`)')
+ (modify-syntax-entry ?\) ")" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\] ")" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\} ")" tablegen-mode-syntax-table)
+ (modify-syntax-entry ?\> ")" tablegen-mode-syntax-table)
+ ;; string quote ('"')
+ (modify-syntax-entry ?\" "\"" tablegen-mode-syntax-table)
+ )
+
+;; --------------------- 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.
+ (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.
+ local-abbrev-table tablegen-mode-abbrev-table
+ font-lock-defaults `(tablegen-font-lock-keywords)
+ require-final-newline t
+ )
+
+ (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 000000000000..b7ffbd9947d5
--- /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"
+
+# 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: //'`
+ld_switches=`llvm-as < /dev/null -o - | llvm-ld - -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
+all_switches="$opt_switches $ld_switches"
+echo "Passes : $all_switches"
+
+# 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=$?
+
+# 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 000000000000..36620d932cb3
--- /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 000000000000..92346572fe01
--- /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 000000000000..fd2f7477bb4e
--- /dev/null
+++ b/utils/fpcmp/Makefile
@@ -0,0 +1,16 @@
+##===- utils/fpcmp/Makefile --------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file 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 000000000000..66d8ab159b93
--- /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 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 000000000000..c8bff8cf833d
--- /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 is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 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 000000000000..c1b950dc34d8
--- /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/jedit/README b/utils/jedit/README
new file mode 100644
index 000000000000..6a6c8c76cc32
--- /dev/null
+++ b/utils/jedit/README
@@ -0,0 +1,14 @@
+-*- llvm/utils/jedit/README -*-
+
+These are syntax highlighting files for the jEdit editor. Included are:
+
+* tablegen.xml
+
+ Syntax highlighting mode for TableGen description files. To use, copy this
+ file to ~/.jedit/modes/ and add this code to your ~/.jedit/modes/catalog:
+
+ <MODE NAME="tablegen" FILE="tablegen.xml" FILE_NAME_GLOB="*.td" />
+
+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/jedit/tablegen.xml b/utils/jedit/tablegen.xml
new file mode 100644
index 000000000000..2d80a3f9732f
--- /dev/null
+++ b/utils/jedit/tablegen.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE MODE SYSTEM "xmode.dtd">
+<MODE>
+ <PROPS>
+ <PROPERTY NAME="lineComment" VALUE="//" />
+ <PROPERTY NAME="commentStart" VALUE="/*" />
+ <PROPERTY NAME="commentEnd" VALUE="*/" />
+ <PROPERTY NAME="indentOpenBrackets" VALUE="{" />
+ <PROPERTY NAME="indentCloseBrackets" VALUE="}" />
+ <PROPERTY NAME="wordBreakChars" VALUE=",+-=&lt;&gt;/?^&amp;*" />
+ <PROPERTY NAME="unalignedOpenBrackets" VALUE="(&lt;" />
+ <PROPERTY NAME="unalignedCloseBrackets" VALUE=")&gt;" />
+ </PROPS>
+ <RULES IGNORE_CASE="FALSE" HIGHLIGHT_DIGITS="TRUE">
+ <EOL_SPAN TYPE="COMMENT1">//</EOL_SPAN>
+ <SPAN TYPE="COMMENT1">
+ <BEGIN>/*</BEGIN>
+ <END>*/</END>
+ </SPAN>
+ <SPAN TYPE="LITERAL1" NO_LINE_BREAK="TRUE" ESCAPE="\">
+ <BEGIN>"</BEGIN>
+ <END>"</END>
+ </SPAN>
+ <KEYWORDS>
+ <KEYWORD1>let</KEYWORD1>
+ <KEYWORD1>def</KEYWORD1>
+ <KEYWORD1>class</KEYWORD1>
+ <KEYWORD1>include</KEYWORD1>
+
+ <KEYWORD3>bit</KEYWORD3>
+ <KEYWORD3>int</KEYWORD3>
+ <KEYWORD3>string</KEYWORD3>
+ <KEYWORD3>bits</KEYWORD3>
+ <KEYWORD3>list</KEYWORD3>
+ <KEYWORD3>dag</KEYWORD3>
+ <KEYWORD3>code</KEYWORD3>
+ </KEYWORDS>
+ </RULES>
+</MODE>
diff --git a/utils/lint/common_lint.py b/utils/lint/common_lint.py
new file mode 100644
index 000000000000..e982680c052a
--- /dev/null
+++ b/utils/lint/common_lint.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+#
+# Common lint functions applicable to multiple types of files.
+
+import re
+
+def VerifyLineLength(filename, lines, max_length):
+ """Checks to make sure the file has no lines with lines exceeding the length
+ limit.
+
+ Args:
+ filename: the file under consideration as string
+ lines: contents of the file as string array
+ max_length: maximum acceptable line length as number
+
+ Returns:
+ A list of tuples with format [(filename, line number, msg), ...] with any
+ violations found.
+ """
+ lint = []
+ line_num = 1
+ for line in lines:
+ length = len(line.rstrip('\n'))
+ if length > max_length:
+ lint.append((filename, line_num,
+ 'Line exceeds %d chars (%d)' % (max_length, length)))
+ line_num += 1
+ return lint
+
+def VerifyTabs(filename, lines):
+ """Checks to make sure the file has no tab characters.
+
+ Args:
+ filename: the file under consideration as string
+ lines: contents of the file as string array
+
+ Returns:
+ A list of tuples with format [(line_number, msg), ...] with any violations
+ found.
+ """
+ lint = []
+ tab_re = re.compile(r'\t')
+ line_num = 1
+ for line in lines:
+ if tab_re.match(line.rstrip('\n')):
+ lint.append((filename, line_num, 'Tab found instead of whitespace'))
+ line_num += 1
+ return lint
+
+
+def VerifyTrailingWhitespace(filename, lines):
+ """Checks to make sure the file has no lines with trailing whitespace.
+
+ Args:
+ filename: the file under consideration as string
+ lines: contents of the file as string array
+
+ Returns:
+ A list of tuples with format [(filename, line number, msg), ...] with any
+ violations found.
+ """
+ lint = []
+ trailing_whitespace_re = re.compile(r'\s+$')
+ line_num = 1
+ for line in lines:
+ if trailing_whitespace_re.match(line.rstrip('\n')):
+ lint.append((filename, line_num, 'Trailing whitespace'))
+ line_num += 1
+ return lint
+
+
+class BaseLint:
+ def RunOnFile(filename, lines):
+ raise Exception('RunOnFile() unimplemented')
+
+
+def RunLintOverAllFiles(linter, filenames):
+ """Runs linter over the contents of all files.
+
+ Args:
+ lint: subclass of BaseLint, implementing RunOnFile()
+ filenames: list of all files whose contents will be linted
+
+ Returns:
+ A list of tuples with format [(filename, line number, msg), ...] with any
+ violations found.
+ """
+ lint = []
+ for filename in filenames:
+ file = open(filename, 'r')
+ if not file:
+ print 'Cound not open %s' % filename
+ continue
+ lines = file.readlines()
+ lint.extend(linter.RunOnFile(filename, lines))
+
+ return lint
diff --git a/utils/lint/cpp_lint.py b/utils/lint/cpp_lint.py
new file mode 100755
index 000000000000..07fad5840fd6
--- /dev/null
+++ b/utils/lint/cpp_lint.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+#
+# Checks C++ files to make sure they conform to LLVM standards, as specified in
+# http://llvm.org/docs/CodingStandards.html .
+#
+# TODO: add unittests for the verifier functions:
+# http://docs.python.org/library/unittest.html .
+
+import common_lint
+import re
+import sys
+
+def VerifyIncludes(filename, lines):
+ """Makes sure the #includes are in proper order and no disallows files are
+ #included.
+
+ Args:
+ filename: the file under consideration as string
+ lines: contents of the file as string array
+ """
+ lint = []
+
+ include_gtest_re = re.compile(r'^#include "gtest/(.*)"')
+ include_llvm_re = re.compile(r'^#include "llvm/(.*)"')
+ include_support_re = re.compile(r'^#include "(Support/.*)"')
+ include_config_re = re.compile(r'^#include "(Config/.*)"')
+ include_system_re = re.compile(r'^#include <(.*)>')
+
+ DISALLOWED_SYSTEM_HEADERS = ['iostream']
+
+ line_num = 1
+ prev_config_header = None
+ prev_system_header = None
+ for line in lines:
+ # TODO: implement private headers
+ # TODO: implement gtest headers
+ # TODO: implement top-level llvm/* headers
+ # TODO: implement llvm/Support/* headers
+
+ # Process Config/* headers
+ config_header = include_config_re.match(line)
+ if config_header:
+ curr_config_header = config_header.group(1)
+ if prev_config_header:
+ if prev_config_header > curr_config_header:
+ lint.append((filename, line_num,
+ 'Config headers not in order: "%s" before "%s"' % (
+ prev_config_header, curr_config_header)))
+
+ # Process system headers
+ system_header = include_system_re.match(line)
+ if system_header:
+ curr_system_header = system_header.group(1)
+
+ # Is it blacklisted?
+ if curr_system_header in DISALLOWED_SYSTEM_HEADERS:
+ lint.append((filename, line_num,
+ 'Disallowed system header: <%s>' % curr_system_header))
+ elif prev_system_header:
+ # Make sure system headers are alphabetized amongst themselves
+ if prev_system_header > curr_system_header:
+ lint.append((filename, line_num,
+ 'System headers not in order: <%s> before <%s>' % (
+ prev_system_header, curr_system_header)))
+
+ prev_system_header = curr_system_header
+
+ line_num += 1
+
+ return lint
+
+
+class CppLint(common_lint.BaseLint):
+ MAX_LINE_LENGTH = 80
+
+ def RunOnFile(self, filename, lines):
+ lint = []
+ lint.extend(VerifyIncludes(filename, lines))
+ lint.extend(common_lint.VerifyLineLength(filename, lines,
+ CppLint.MAX_LINE_LENGTH))
+ lint.extend(common_lint.VerifyTabs(filename, lines))
+ lint.extend(common_lint.VerifyTrailingWhitespace(filename, lines))
+ return lint
+
+
+def CppLintMain(filenames):
+ all_lint = common_lint.RunLintOverAllFiles(CppLint(), filenames)
+ for lint in all_lint:
+ print '%s:%d:%s' % (lint[0], lint[1], lint[2])
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(CppLintMain(sys.argv[1:]))
diff --git a/utils/lint/generic_lint.py b/utils/lint/generic_lint.py
new file mode 100755
index 000000000000..c8f4835bb6a6
--- /dev/null
+++ b/utils/lint/generic_lint.py
@@ -0,0 +1,24 @@
+#!/usr/bin/python
+#
+# Checks files to make sure they conform to LLVM standards which can be applied
+# to any programming language: at present, line length and trailing whitespace.
+
+import common_lint
+import sys
+
+class GenericCodeLint(common_lint.BaseLint):
+ MAX_LINE_LENGTH = 80
+
+ def RunOnFile(self, filename, lines):
+ common_lint.VerifyLineLength(filename, lines,
+ GenericCodeLint.MAX_LINE_LENGTH)
+ common_lint.VerifyTrailingWhitespace(filename, lines)
+
+
+def GenericCodeLintMain(filenames):
+ common_lint.RunLintOverAllFiles(GenericCodeLint(), filenames)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(GenericCodeLintMain(sys.argv[1:]))
diff --git a/utils/lint/remove_trailing_whitespace.sh b/utils/lint/remove_trailing_whitespace.sh
new file mode 100755
index 000000000000..6e0c9be0932b
--- /dev/null
+++ b/utils/lint/remove_trailing_whitespace.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Deletes trailing whitespace in-place in the passed-in files.
+# Sample syntax:
+# $0 *.cpp
+
+perl -pi -e 's/\s+$/\n/' $*
diff --git a/utils/llvm-native-gcc b/utils/llvm-native-gcc
new file mode 100755
index 000000000000..b3cecb14118f
--- /dev/null
+++ b/utils/llvm-native-gcc
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+# Wrapper around LLVM tools to generate a native .o from llvm-gcc using an
+# LLVM back-end (CBE by default).
+
+# set up defaults.
+$Verbose = 0;
+$SaveTemps = 1;
+$PreprocessOnly = 0;
+$CompileDontLink = 0;
+$Backend = 'cbe';
+chomp ($ProgramName = `basename $0`);
+
+sub boldprint {
+ print "", @_, "";
+}
+
+# process command-line options.
+# most of these are passed on to llvm-gcc.
+$GCCOptions = "";
+for ($i = 0; $i <= $#ARGV; ++$i) {
+ if ($ARGV[$i] =~ /-mllvm-backend=([a-z0-9]*)/) {
+ $Backend = $1;
+ if ($ProgramName =~ /llvm-native-gcc/) {
+ splice (@ARGV, $i, 1);
+ --$i;
+ }
+ } elsif ($ARGV[$i] eq "-E") {
+ $PreprocessOnly = 1;
+ } elsif ($ARGV[$i] eq "-c") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $CompileDontLink = 1;
+ } elsif ($ARGV[$i] eq "-v") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $Verbose = 1;
+ } elsif ($ARGV[$i] eq "-o") {
+ $OutputFile = $ARGV[$i + 1];
+ } elsif ($ARGV[$i] eq "-save-temps") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $SaveTemps = 1;
+ } elsif ($ARGV[$i] =~ /\.bc$/) {
+ push (@BytecodeFiles, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-L/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@LibDirs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-l/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@Libs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /\.(c|cpp|cc|i|ii|C)$/) {
+ $LastCFile = $ARGV[$i];
+ }
+}
+
+sub GetDefaultOutputFileName {
+ my $DefaultOutputFileBase;
+
+ if ($ProgramName =~ /llvm-native-gcc/) {
+ $DefaultOutputFileBase = $LastCFile;
+ } elsif ($ProgramName =~ /native-build/) {
+ $DefaultOutputFileBase = $BytecodeFiles[0];
+ }
+
+ my $def = $DefaultOutputFileBase;
+
+ die "Can't figure out name of output file.\n"
+ unless $DefaultOutputFileBase
+ && (($ProgramName !~ /native-build/)
+ || $#BytecodeFiles == 0);
+
+ print "Warning: defaulting output file name ",
+ "based on '$DefaultOutputFileBase'\n" if $Verbose;
+
+ if ($ProgramName =~ /llvm-native-gcc/) {
+ $def =~ s/\.(c|cpp|cc|i|ii|C)$/.o/;
+ } elsif ($ProgramName =~ /native-build/) {
+ $def =~ s/\.bc$/.$Backend/;
+ if ($CompileDontLink) {
+ $def .= ".o";
+ }
+ }
+
+ return $def;
+}
+
+# run a command, optionally echoing, and quitting if it fails:
+sub run {
+ my $command = join(" ", @_);
+ print "$command\n" if $Verbose;
+ $command =~ s/\"/\\\"/g;
+ system $command and die "$0: $command failed";
+}
+
+sub LinkBytecodeFilesIntoTemporary {
+ my $FinalOutputFileName = shift @_;
+ my @BytecodeFiles = @_;
+
+ my $BCFiles = join (" ", @BytecodeFiles);
+ my $LinkedBCFile;
+ if ($SaveTemps) {
+ $LinkedBCFile = "${FinalOutputFileName}.llvm.bc";
+ } else {
+ $LinkedBCFile = "/tmp/nativebuild-$$.llvm.bc";
+ }
+ run "llvm-link -o $LinkedBCFile $BCFiles";
+ return $LinkedBCFile;
+}
+
+sub CompileBytecodeToNative {
+ my ($BCFile, $Backend, $OutputFile) = @_;
+
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.c";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.c";
+ }
+ run "llc -enable-correct-eh-support -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.s";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.s";
+ }
+ run "llc -enable-correct-eh-support -f -o $GeneratedCode $BCFile";
+ }
+ my $LibDirs = join (" ", @LibDirs);
+ my $Libs = join (" ", @Libs);
+ run "gcc $GCCOptions $GeneratedCode -o $OutputFile $LibDirs $Libs";
+ run "rm $BCFile $GeneratedCode"
+ unless $SaveTemps;
+}
+
+sub CompileCToNative {
+ my ($LLVMGCCCommand, $Backend, $OutputFile) = @_;
+ run $LLVMGCCCommand;
+ if ($PreprocessOnly) {
+ return;
+ }
+ my $BCFile = "${OutputFile}.llvm.bc";
+ if ($CompileDontLink) {
+ run "mv ${OutputFile} $BCFile";
+ } else { # gccld messes with the output file name
+ run "mv ${OutputFile}.bc $BCFile";
+ }
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ $GeneratedCode = "${OutputFile}.cbe.c";
+ run "llc -enable-correct-eh-support -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ $GeneratedCode = "${OutputFile}.llc.s";
+ run "llc -enable-correct-eh-support -f -o $GeneratedCode $BCFile";
+ }
+ my $NativeGCCOptions = "";
+ if ($CompileDontLink) {
+ $NativeGCCOptions = "-c";
+ }
+ run "gcc $NativeGCCOptions $GeneratedCode -o $OutputFile";
+ run "rm ${OutputFile}.llvm.bc $GeneratedCode"
+ unless $SaveTemps;
+}
+
+# guess the name of the output file, if -o was not specified.
+$OutputFile = GetDefaultOutputFileName () unless $OutputFile;
+print "Output file is $OutputFile\n" if $Verbose;
+# do all the dirty work:
+if ($ProgramName eq /native-build/) {
+ my $LinkedBCFile = LinkBytecodeFilesIntoTemporary (@BytecodeFiles);
+ CompileBytecodeToNative ($LinkedBCFile, $Backend, $OutputFile);
+} elsif ($ProgramName =~ /llvm-native-gcc/) {
+ # build the llvm-gcc command line.
+ $LLVMGCCCommand = join (" ", ("llvm-gcc", @ARGV));
+ CompileCToNative ($LLVMGCCCommand, $Backend, $OutputFile);
+}
+
+# we're done.
+exit 0;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+llvm-native-gcc
+
+=head1 SYNOPSIS
+
+llvm-native-gcc [OPTIONS...] FILE
+
+native-build [OPTIONS...] FILE
+
+=head1 DESCRIPTION
+
+llvm-native-gcc is a wrapper around the LLVM command-line tools which generates
+a native object (.o) file by compiling FILE with llvm-gcc, and then running
+an LLVM back-end (CBE by default) over the resulting bytecode, and then
+compiling the resulting code to a native object file.
+
+If called as "native-build", it compiles bytecode to native code, and takes
+different options.
+
+=head1 OPTIONS
+
+llvm-native-gcc takes the same options as llvm-gcc. All options
+except -mllvm-backend=... are passed on to llvm-gcc.
+
+=over 4
+
+=item -mllvm-backend=BACKEND
+
+Use BACKEND for native code generation.
+
+=item -v
+
+Print command lines that llvm-native-gcc runs.
+
+=item -o FILE
+
+llvm-native-gcc tries to guess the name of the llvm-gcc output file by looking
+for this option in the command line. If it can't find it, it finds the last C
+or C++ source file named on the command line, and turns its suffix into .o. See
+BUGS.
+
+=item -save-temps
+
+Save temporary files used by llvm-native-gcc (and llvm-gcc, and gcc).
+
+=back
+
+=head1 BUGS
+
+llvm-native-gcc only handles the case where llvm-gcc compiles a single
+file per invocation. llvm-native-gcc has weak command-line argument
+parsing and is a poor substitute for making gcc/gcc.c do this stuff.
+
+This manual page does not adequately document native-build mode.
+
+llvm-native-gcc is pretty gross because it represents the blind merging of two
+other scripts that predated it. It could use some code clean-up.
+
+=head1 SEE ALSO
+
+gcc(1)
+
+=head1 AUTHOR
+
+Brian R. Gaeke
+
+=cut
diff --git a/utils/llvm-native-gxx b/utils/llvm-native-gxx
new file mode 100755
index 000000000000..75164af237ef
--- /dev/null
+++ b/utils/llvm-native-gxx
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+# Wrapper around LLVM tools to generate a native .o from llvm-gxx using an
+# LLVM back-end (CBE by default).
+
+# set up defaults.
+$Verbose = 0;
+$SaveTemps = 1;
+$PreprocessOnly = 0;
+$CompileDontLink = 0;
+$Backend = 'cbe';
+chomp ($ProgramName = `basename $0`);
+
+sub boldprint {
+ print "", @_, "";
+}
+
+# process command-line options.
+# most of these are passed on to llvm-gxx.
+$GCCOptions = "";
+for ($i = 0; $i <= $#ARGV; ++$i) {
+ if ($ARGV[$i] =~ /-mllvm-backend=([a-z0-9]*)/) {
+ $Backend = $1;
+ if ($ProgramName =~ /llvm-native-gxx/) {
+ splice (@ARGV, $i, 1);
+ --$i;
+ }
+ } elsif ($ARGV[$i] eq "-E") {
+ $PreprocessOnly = 1;
+ } elsif ($ARGV[$i] eq "-c") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $CompileDontLink = 1;
+ } elsif ($ARGV[$i] eq "-v") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $Verbose = 1;
+ } elsif ($ARGV[$i] eq "-o") {
+ $OutputFile = $ARGV[$i + 1];
+ } elsif ($ARGV[$i] eq "-save-temps") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $SaveTemps = 1;
+ } elsif ($ARGV[$i] =~ /\.bc$/) {
+ push (@BytecodeFiles, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-L/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@LibDirs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-l/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@Libs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /\.(c|cpp|cc|i|ii|C)$/) {
+ $LastCFile = $ARGV[$i];
+ }
+}
+
+sub GetDefaultOutputFileName {
+ my $DefaultOutputFileBase;
+
+ if ($ProgramName =~ /llvm-native-gxx/) {
+ $DefaultOutputFileBase = $LastCFile;
+ } elsif ($ProgramName =~ /native-build/) {
+ $DefaultOutputFileBase = $BytecodeFiles[0];
+ }
+
+ my $def = $DefaultOutputFileBase;
+
+ die "Can't figure out name of output file.\n"
+ unless $DefaultOutputFileBase
+ && (($ProgramName !~ /native-build/)
+ || $#BytecodeFiles == 0);
+
+ print "Warning: defaulting output file name ",
+ "based on '$DefaultOutputFileBase'\n" if $Verbose;
+
+ if ($ProgramName =~ /llvm-native-gxx/) {
+ $def =~ s/\.(c|cpp|cc|i|ii|C)$/.o/;
+ } elsif ($ProgramName =~ /native-build/) {
+ $def =~ s/\.bc$/.$Backend/;
+ if ($CompileDontLink) {
+ $def .= ".o";
+ }
+ }
+
+ return $def;
+}
+
+# run a command, optionally echoing, and quitting if it fails:
+sub run {
+ my $command = join(" ", @_);
+ print "$command\n" if $Verbose;
+ $command =~ s/\"/\\\"/g;
+ system $command and die "$0: $command failed";
+}
+
+sub LinkBytecodeFilesIntoTemporary {
+ my $FinalOutputFileName = shift @_;
+ my @BytecodeFiles = @_;
+
+ my $BCFiles = join (" ", @BytecodeFiles);
+ my $LinkedBCFile;
+ if ($SaveTemps) {
+ $LinkedBCFile = "${FinalOutputFileName}.llvm.bc";
+ } else {
+ $LinkedBCFile = "/tmp/nativebuild-$$.llvm.bc";
+ }
+ run "llvm-link -o $LinkedBCFile $BCFiles";
+ return $LinkedBCFile;
+}
+
+sub CompileBytecodeToNative {
+ my ($BCFile, $Backend, $OutputFile) = @_;
+
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.c";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.c";
+ }
+ run "llc -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.s";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.s";
+ }
+ run "llc -f -o $GeneratedCode $BCFile";
+ }
+ my $LibDirs = join (" ", @LibDirs);
+ my $Libs = join (" ", @Libs);
+ run "gcc $GCCOptions $GeneratedCode -o $OutputFile $LibDirs $Libs";
+ run "rm $BCFile $GeneratedCode"
+ unless $SaveTemps;
+}
+
+sub CompileCToNative {
+ my ($LLVMGCCCommand, $Backend, $OutputFile) = @_;
+ run $LLVMGCCCommand;
+ if ($PreprocessOnly) {
+ return;
+ }
+ my $BCFile = "${OutputFile}.llvm.bc";
+ if ($CompileDontLink) {
+ run "mv ${OutputFile} $BCFile";
+ } else { # gccld messes with the output file name
+ run "mv ${OutputFile}.bc $BCFile";
+ }
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ $GeneratedCode = "${OutputFile}.cbe.c";
+ run "llc -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ $GeneratedCode = "${OutputFile}.llc.s";
+ run "llc -f -o $GeneratedCode $BCFile";
+ }
+ my $NativeGCCOptions = "";
+ if ($CompileDontLink) {
+ $NativeGCCOptions = "-c";
+ }
+ run "gcc $NativeGCCOptions $GeneratedCode -o $OutputFile";
+ run "rm ${OutputFile}.llvm.bc $GeneratedCode"
+ unless $SaveTemps;
+}
+
+# guess the name of the output file, if -o was not specified.
+$OutputFile = GetDefaultOutputFileName () unless $OutputFile;
+print "Output file is $OutputFile\n" if $Verbose;
+# do all the dirty work:
+if ($ProgramName eq /native-build/) {
+ my $LinkedBCFile = LinkBytecodeFilesIntoTemporary (@BytecodeFiles);
+ CompileBytecodeToNative ($LinkedBCFile, $Backend, $OutputFile);
+} elsif ($ProgramName =~ /llvm-native-gxx/) {
+ # build the llvm-gxx command line.
+ $LLVMGCCCommand = join (" ", ("llvm-g++", @ARGV));
+ CompileCToNative ($LLVMGCCCommand, $Backend, $OutputFile);
+}
+
+# we're done.
+exit 0;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+llvm-native-gxx
+
+=head1 SYNOPSIS
+
+llvm-native-g++ [OPTIONS...] FILE
+
+native-build [OPTIONS...] FILE
+
+=head1 DESCRIPTION
+
+llvm-native-g++ is a wrapper around the LLVM command-line tools which generates
+a native object (.o) file by compiling FILE with llvm-g++, and then running
+an LLVM back-end (CBE by default) over the resulting bytecode, and then
+compiling the resulting code to a native object file.
+
+If called as "native-build", it compiles bytecode to native code, and takes
+different options.
+
+=head1 OPTIONS
+
+llvm-native-g++ takes the same options as llvm-gcc. All options
+except -mllvm-backend=... are passed on to llvm-g++.
+
+=over 4
+
+=item -mllvm-backend=BACKEND
+
+Use BACKEND for native code generation.
+
+=item -v
+
+Print command lines that llvm-native-g++ runs.
+
+=item -o FILE
+
+llvm-native-g++ tries to guess the name of the llvm-g++ output file by looking
+for this option in the command line. If it can't find it, it finds the last C
+or C++ source file named on the command line, and turns its suffix into .o. See
+BUGS.
+
+=item -save-temps
+
+Save temporary files used by llvm-native-g++ (and llvm-g++, and g++).
+
+=back
+
+=head1 BUGS
+
+llvm-native-g++ only handles the case where llvm-g++ compiles a single
+file per invocation. llvm-native-g++ has weak command-line argument
+parsing and is a poor substitute for making g++/g++.c do this stuff.
+
+This manual page does not adequately document native-build mode.
+
+llvm-native-g++ is pretty gross because it represents the blind merging of two
+other scripts that predated it. It could use some code clean-up.
+
+=head1 SEE ALSO
+
+g++(1)
+
+=head1 AUTHOR
+
+Brian R. Gaeke
+
+=cut
diff --git a/utils/llvm.grm b/utils/llvm.grm
new file mode 100644
index 000000000000..05083bfede6a
--- /dev/null
+++ b/utils/llvm.grm
@@ -0,0 +1,409 @@
+(*
+
+polygen grammar for LLVM assembly language.
+
+This file defines an LLVM assembly language grammar for polygen,
+which is a tool for generating random text based on a grammar.
+It is strictly syntax-based, and makes no attempt to generate
+IR that is semantically valid. Most of the IR produced doesn't
+pass the Verifier.
+
+*)
+
+I ::= "title: LLVM assembly language\n"
+ ^ "status: experimental\n"
+ ^ "audience: LLVM developers\n"
+;
+
+S ::= Module ;
+
+(*
+Define rules for non-keyword tokens. This is currently just a bunch
+of hacks. They don't cover many valid forms of tokens, and they also
+generate some invalid forms of tokens. The LLVM parser has custom
+C++ code to lex these; custom C++ code for emitting them would be
+convenient, but polygen doesn't support that.
+*)
+NonZeroDecimalDigit ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ;
+DecimalDigit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ;
+DecimalDigitSeq ::= DecimalDigit [^ DecimalDigitSeq ];
+HexDigit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
+ | a | b | c | d | e | f ;
+HexDigitSeq ::= HexDigit [^ HexDigitSeq ];
+StringChar ::= a | b | c | d | e | f | g | h | i | j | k | l | m
+ | n | o | p | q | r | s | t | u | v | w | x | y | z ;
+StringConstantSeq ::= StringChar [^ StringConstantSeq ];
+StringConstant ::= StringChar [^ StringConstantSeq ];
+EUINT64VAL ::= NonZeroDecimalDigit [^ DecimalDigitSeq ];
+ESINT64VAL ::= [ "-" ] ^ EUINT64VAL ;
+EUAPINTVAL ::= EUINT64VAL ;
+ESAPINTVAL ::= ESINT64VAL ;
+LOCALVALID ::= "%" ^ DecimalDigitSeq ;
+GLOBALVALID ::= "@" ^ DecimalDigitSeq ;
+INTTYPE ::= "i" ^ EUINT64VAL ;
+GLOBALVAR ::= "@" ^ StringConstant ;
+LOCALVAR ::= "%" ^ StringConstant ;
+STRINGCONSTANT ::= "\"" ^ StringConstant ^ "\"" ;
+ATSTRINGCONSTANT ::= "@" ^ STRINGCONSTANT ;
+PCTSTRINGCONSTANT ::= "%" ^ STRINGCONSTANT ;
+LABELSTR ::= StringConstant ;
+FPVAL ::= ESAPINTVAL ^ "." ^ EUAPINTVAL | "0x" ^ HexDigitSeq ;
+
+(*
+The rest of this file is derived directly from llvmAsmParser.y.
+*)
+
+ArithmeticOps ::= add | sub | mul | udiv | sdiv | fdiv | urem | srem | frem ;
+LogicalOps ::= shl | lshr | ashr | and | or | xor;
+CastOps ::= trunc | zext | sext | fptrunc | fpext | bitcast |
+ uitofp | sitofp | fptoui | fptosi | inttoptr | ptrtoint ;
+
+IPredicates ::= eq | ne | slt | sgt | sle | sge | ult | ugt | ule | uge ;
+
+FPredicates ::= oeq | one | olt | ogt | ole | oge | ord | uno | ueq | une
+ | ult | ugt | ule | uge | true | false ;
+
+IntType ::= INTTYPE;
+FPType ::= float | double | "ppc_fp128" | fp128 | "x86_fp80";
+
+LocalName ::= LOCALVAR | STRINGCONSTANT | PCTSTRINGCONSTANT ;
+OptLocalName ::= LocalName | _ ;
+
+OptAddrSpace ::= - addrspace ^ "(" ^ EUINT64VAL ^ ")" | _ ;
+
+OptLocalAssign ::= LocalName "=" | _ ;
+
+GlobalName ::= GLOBALVAR | ATSTRINGCONSTANT ;
+
+OptGlobalAssign ::= GlobalAssign | _ ;
+
+GlobalAssign ::= GlobalName "=" ;
+
+GVInternalLinkage
+ ::= + internal
+ | weak
+ | "weak_odr"
+ | linkonce
+ | "linkonce_odr"
+ | appending
+ | dllexport
+ | common
+ ;
+
+GVExternalLinkage
+ ::= dllimport
+ | "extern_weak"
+ | + external
+ ;
+
+GVVisibilityStyle
+ ::= + _
+ | default
+ | hidden
+ | protected
+ ;
+
+FunctionDeclareLinkage
+ ::= + _
+ | dllimport
+ | "extern_weak"
+ ;
+
+FunctionDefineLinkage
+ ::= + _
+ | internal
+ | linkonce
+ | "linkonce_odr"
+ | weak
+ | "weak_odr"
+ | dllexport
+ ;
+
+AliasLinkage ::= + _ | weak | "weak_odr" | internal ;
+
+OptCallingConv ::= + _ |
+ ccc |
+ fastcc |
+ coldcc |
+ "x86_stdcallcc" |
+ "x86_fastcallcc" |
+ cc EUINT64VAL ;
+
+ParamAttr ::= zeroext
+ | signext
+ | inreg
+ | sret
+ | noalias
+ | nocapture
+ | byval
+ | nest
+ | align EUINT64VAL
+ ;
+
+OptParamAttrs ::= + _ | OptParamAttrs ParamAttr ;
+
+RetAttr ::= inreg
+ | zeroext
+ | signext
+ | noalias
+ ;
+
+OptRetAttrs ::= _
+ | OptRetAttrs RetAttr
+ ;
+
+FuncAttr ::= noreturn
+ | nounwind
+ | inreg
+ | zeroext
+ | signext
+ | readnone
+ | readonly
+ | noinline
+ | alwaysinline
+ | optsize
+ | ssp
+ | sspreq
+ ;
+
+OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
+
+OptGC ::= + _ | gc STRINGCONSTANT ;
+
+OptAlign ::= + _ | align EUINT64VAL ;
+OptCAlign ::= + _ | ^ "," align EUINT64VAL ;
+
+SectionString ::= section STRINGCONSTANT ;
+
+OptSection ::= + _ | SectionString ;
+
+GlobalVarAttributes ::= + _ | ^ "," GlobalVarAttribute GlobalVarAttributes ;
+GlobalVarAttribute ::= SectionString | align EUINT64VAL ;
+
+PrimType ::= INTTYPE | float | double | "ppc_fp128" | fp128 | "x86_fp80"
+ | - label ;
+
+Types
+ ::= opaque
+ | PrimType
+ | Types OptAddrSpace ^ "*"
+ | SymbolicValueRef
+ | "\\" ^ EUINT64VAL
+ | Types "(" ^ ArgTypeListI ^ ")" OptFuncAttrs
+ | void "(" ^ ArgTypeListI ^ ")" OptFuncAttrs
+ | "[" ^ EUINT64VAL "x" Types ^ "]"
+ | "<" ^ EUINT64VAL "x" Types ^ ">"
+ | "{" TypeListI "}"
+ | "{" ^ "}"
+ | "<" ^ "{" TypeListI "}" ^ ">"
+ | "<" ^ "{" ^ "}" ^ ">"
+ ;
+
+ArgType ::= Types OptParamAttrs ;
+
+ResultTypes ::= Types | void ;
+
+ArgTypeList ::= ArgType | ArgTypeList ^ "," ArgType ;
+
+ArgTypeListI ::= ArgTypeList | ArgTypeList ^ "," "..." | "..." | _ ;
+
+TypeListI ::= Types | TypeListI ^ "," Types ;
+
+ConstVal::= Types "[" ^ ConstVector ^ "]"
+ | Types "[" ^ "]"
+ | Types "c" ^ STRINGCONSTANT
+ | Types "<" ^ ConstVector ^ ">"
+ | Types "{" ConstVector "}"
+ | Types "{" ^ "}"
+ | Types "<" ^ "{" ConstVector "}" ^ ">"
+ | Types "<" ^ "{" ^ "}" ^ ">"
+ | Types null
+ | Types undef
+ | Types SymbolicValueRef
+ | Types ConstExpr
+ | Types zeroinitializer
+ | Types ESINT64VAL
+ | Types ESAPINTVAL
+ | Types EUINT64VAL
+ | Types EUAPINTVAL
+ | Types true
+ | Types false
+ | Types FPVAL ;
+
+ConstExpr::= CastOps "(" ^ ConstVal to Types ^ ")"
+ | getelementptr "(" ^ ConstVal IndexList ^ ")"
+ | select "(" ^ ConstVal ^ "," ConstVal ^ "," ConstVal ^ ")"
+ | ArithmeticOps "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | LogicalOps "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | icmp IPredicates "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | fcmp FPredicates "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | vicmp IPredicates "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | vfcmp FPredicates "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | extractelement "(" ^ ConstVal ^ "," ConstVal ^ ")"
+ | insertelement "(" ^ ConstVal ^ "," ConstVal ^ "," ConstVal ^ ")"
+ | shufflevector "(" ^ ConstVal ^ "," ConstVal ^ "," ConstVal ^ ")"
+ | extractvalue "(" ^ ConstVal ^ ConstantIndexList ^ ")"
+ | insertvalue "(" ^ ConstVal ^ "," ConstVal ^ ConstantIndexList ^ ")" ;
+
+ConstVector ::= ConstVector ^ "," ConstVal | ConstVal ;
+
+GlobalType ::= global | constant ;
+
+ThreadLocal ::= - "thread_local" | _ ;
+
+AliaseeRef ::= ResultTypes SymbolicValueRef
+ | bitcast "(" ^ AliaseeRef to Types ^ ")" ;
+
+Module ::= +++ DefinitionList | --- _ ;
+
+DefinitionList ::= - Definition | + DefinitionList Definition ;
+
+Definition
+ ::= ^ ( +++++ define Function
+ | declare FunctionProto
+ | - module asm AsmBlock
+ | OptLocalAssign type Types
+ | OptGlobalAssign GVVisibilityStyle ThreadLocal OptAddrSpace GlobalType
+ ConstVal GlobalVarAttributes
+ | OptGlobalAssign GVInternalLinkage GVVisibilityStyle ThreadLocal OptAddrSpace
+ GlobalType ConstVal GlobalVarAttributes
+ | OptGlobalAssign GVExternalLinkage GVVisibilityStyle ThreadLocal OptAddrSpace
+ GlobalType Types GlobalVarAttributes
+ | OptGlobalAssign GVVisibilityStyle alias AliasLinkage AliaseeRef
+ | target TargetDefinition
+ | deplibs "=" LibrariesDefinition
+ ) ^ "\n";
+
+AsmBlock ::= STRINGCONSTANT ;
+
+TargetDefinition ::= triple "=" STRINGCONSTANT
+ | datalayout "=" STRINGCONSTANT ;
+
+LibrariesDefinition ::= "[" ( LibList | _ ) "]";
+
+LibList ::= LibList ^ "," STRINGCONSTANT | STRINGCONSTANT ;
+
+ArgListH ::= ArgListH ^ "," Types OptParamAttrs OptLocalName
+ | Types OptParamAttrs OptLocalName ;
+
+ArgList ::= ArgListH | ArgListH ^ "," "..." | "..." | _ ;
+
+FunctionHeaderH ::= OptCallingConv OptRetAttrs ResultTypes
+ GlobalName ^ "(" ^ ArgList ^ ")"
+ OptFuncAttrs OptSection OptAlign OptGC ;
+
+BEGIN ::= ( begin | "{" ) ^ "\n";
+
+FunctionHeader ::=
+ FunctionDefineLinkage GVVisibilityStyle FunctionHeaderH BEGIN ;
+
+END ::= ^ ( end | "}" ) ^ "\n";
+
+Function ::= BasicBlockList END ;
+
+FunctionProto ::= FunctionDeclareLinkage GVVisibilityStyle FunctionHeaderH ;
+
+OptSideEffect ::= _ | sideeffect ;
+
+ConstValueRef ::= ESINT64VAL
+ | EUINT64VAL
+ | FPVAL
+ | true
+ | false
+ | null
+ | undef
+ | zeroinitializer
+ | "<" ConstVector ">"
+ | "[" ConstVector "]"
+ | "[" ^ "]"
+ | "c" ^ STRINGCONSTANT
+ | "{" ConstVector "}"
+ | "{" ^ "}"
+ | "<" ^ "{" ConstVector "}" ^ ">"
+ | "<" ^ "{" ^ "}" ^ ">"
+ | ConstExpr
+ | asm OptSideEffect STRINGCONSTANT ^ "," STRINGCONSTANT ;
+
+SymbolicValueRef ::= LOCALVALID
+ | GLOBALVALID
+ | LocalName
+ | GlobalName ;
+
+ValueRef ::= SymbolicValueRef | ConstValueRef;
+
+ResolvedVal ::= Types ValueRef ;
+
+ReturnedVal ::= ResolvedVal | ReturnedVal ^ "," ResolvedVal ;
+
+BasicBlockList ::= BasicBlockList BasicBlock | FunctionHeader BasicBlock ;
+
+BasicBlock ::= InstructionList OptLocalAssign BBTerminatorInst ;
+
+InstructionList ::= +++ InstructionList Inst
+ | - _
+ | ^ LABELSTR ^ ":\n" ;
+
+BBTerminatorInst ::= ^ " " ^
+ ( ret ReturnedVal
+ | ret void
+ | br label ValueRef
+ | br INTTYPE ValueRef ^ "," label ValueRef ^ "," label ValueRef
+ | switch IntType ValueRef ^ "," label ValueRef "[" JumpTable "]"
+ | switch IntType ValueRef ^ "," label ValueRef "[" ^ "]"
+ | invoke OptCallingConv ResultTypes ValueRef ^ "(" ^ ParamList ^ ")"
+ OptFuncAttrs
+ to label ValueRef unwind label ValueRef
+ | unwind
+ | unreachable ) ^ "\n";
+
+JumpTable ::= JumpTable IntType ConstValueRef ^ "," label ValueRef
+ | IntType ConstValueRef ^ "," label ValueRef ;
+
+Inst ::= ^ " " ^ OptLocalAssign InstVal ^ "\n";
+
+PHIList ::= Types "[" ValueRef ^ "," ValueRef "]"
+ | PHIList ^ "," "[" ValueRef ^ "," ValueRef "]" ;
+
+ParamList ::= Types OptParamAttrs ValueRef OptParamAttrs
+ | label OptParamAttrs ValueRef OptParamAttrs
+ | ParamList ^ "," Types OptParamAttrs ValueRef OptParamAttrs
+ | ParamList ^ "," label OptParamAttrs ValueRef OptParamAttrs
+ | - _ ;
+
+IndexList ::= _ | IndexList ^ "," ResolvedVal ;
+
+ConstantIndexList ::= "," EUINT64VAL | ConstantIndexList ^ "," EUINT64VAL ;
+
+OptTailCall ::= tail call | call ;
+
+InstVal ::=
+ ArithmeticOps Types ValueRef ^ "," ValueRef
+ | LogicalOps Types ValueRef ^ "," ValueRef
+ | icmp IPredicates Types ValueRef ^ "," ValueRef
+ | fcmp FPredicates Types ValueRef ^ "," ValueRef
+ | vicmp IPredicates Types ValueRef ^ "," ValueRef
+ | vfcmp FPredicates Types ValueRef ^ "," ValueRef
+ | CastOps ResolvedVal to Types
+ | select ResolvedVal ^ "," ResolvedVal ^ "," ResolvedVal
+ | "va_arg" ResolvedVal ^ "," Types
+ | extractelement ResolvedVal ^ "," ResolvedVal
+ | insertelement ResolvedVal ^ "," ResolvedVal ^ "," ResolvedVal
+ | shufflevector ResolvedVal ^ "," ResolvedVal ^ "," ResolvedVal
+ | phi PHIList
+ | OptTailCall OptCallingConv ResultTypes ValueRef ^ "(" ^ ParamList ^ ")"
+ OptFuncAttrs
+ | MemoryInst ;
+
+OptVolatile ::= - volatile | _ ;
+
+MemoryInst ::= malloc Types OptCAlign
+ | malloc Types ^ "," INTTYPE ValueRef OptCAlign
+ | alloca Types OptCAlign
+ | alloca Types ^ "," INTTYPE ValueRef OptCAlign
+ | free ResolvedVal
+ | OptVolatile load Types ValueRef OptCAlign
+ | OptVolatile store ResolvedVal ^ "," Types ValueRef OptCAlign
+ | getresult Types ValueRef ^ "," EUINT64VAL
+ | getelementptr Types ValueRef IndexList
+ | extractvalue Types ValueRef ^ ConstantIndexList
+ | insertvalue Types ValueRef ^ "," Types ValueRef ^ ConstantIndexList ;
diff --git a/utils/llvmdo b/utils/llvmdo
new file mode 100755
index 000000000000..b666f2209b06
--- /dev/null
+++ b/utils/llvmdo
@@ -0,0 +1,188 @@
+#!/bin/sh
+##===- utils/llvmdo - Counts Lines Of Code -------------------*- Script -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file 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 *LoopSimplifyCrash.ll \
+ -o -name *AST-Remove.ll \
+ -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 000000000000..7d7355ba9904
--- /dev/null
+++ b/utils/llvmgrep
@@ -0,0 +1,39 @@
+#!/bin/sh
+##===- utils/llvmgrep - Counts Lines Of Code -----------------*- Script -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file 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 000000000000..ae77712941a2
--- /dev/null
+++ b/utils/makellvm
@@ -0,0 +1,145 @@
+#!/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"
+ set pstatus = $?
+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 000000000000..d256d98f6f3d
--- /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 > "$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/Bitcode lib/Analysis lib/Transforms lib/CodeGen lib/Target \
+ lib/ExecutionEngine lib/Debugger lib/Linker \
+ tools test unittests 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 000000000000..95afca73a132
--- /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 000000000000..55d503d68933
--- /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 000000000000..f9950f97fea8
--- /dev/null
+++ b/utils/profile.pl
@@ -0,0 +1,74 @@
+#!/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 $libdir = `llvm-config --libdir`;
+chomp $libdir;
+
+my $LibProfPath = $libdir . "/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/unittest/Makefile b/utils/unittest/Makefile
new file mode 100644
index 000000000000..2f3e601b41b7
--- /dev/null
+++ b/utils/unittest/Makefile
@@ -0,0 +1,13 @@
+##===- utils/unittest/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+PARALLEL_DIRS = googletest
+
+include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/googletest/LICENSE.TXT b/utils/unittest/googletest/LICENSE.TXT
new file mode 100644
index 000000000000..1941a11f8ce9
--- /dev/null
+++ b/utils/unittest/googletest/LICENSE.TXT
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile
new file mode 100644
index 000000000000..d709878449a6
--- /dev/null
+++ b/utils/unittest/googletest/Makefile
@@ -0,0 +1,27 @@
+##===- utils/unittest/googletest/Makefile ------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../../..
+include $(LEVEL)/Makefile.config
+NO_MISSING_FIELD_INITIALIZERS := $(shell $(CXX) -Wno-missing-field-initializers -fsyntax-only -xc /dev/null 2>/dev/null && echo -Wno-missing-field-initializers)
+NO_VARIADIC_MACROS := $(shell $(CXX) -Wno-variadic-macros -fsyntax-only -xc /dev/null 2>/dev/null && echo -Wno-variadic-macros)
+
+
+LIBRARYNAME = GoogleTest
+BUILD_ARCHIVE = 1
+CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include/
+CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS)
+
+ifeq ($(OS),MingW)
+ CPP.Flags += -DGTEST_OS_WINDOWS=1
+endif
+
+NO_INSTALL = 1
+
+include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/googletest/README.LLVM b/utils/unittest/googletest/README.LLVM
new file mode 100644
index 000000000000..2c673cc6ab74
--- /dev/null
+++ b/utils/unittest/googletest/README.LLVM
@@ -0,0 +1,26 @@
+LLVM notes
+----------
+
+This directory contains Google Test 1.2.1, with all elements removed except for
+the actual source code, to minimize the addition to the LLVM distribution.
+
+Cleaned up as follows:
+
+# Remove all the unnecessary files and directories
+$ rm -f aclocal* configure* Makefile* CHANGES CONTRIBUTORS README
+$ rm -rf build-aux m4 make msvc samples scons scripts test xcode
+$ rm -f `find . -name \*\.pump`
+
+# Move all the source files to the current directory
+$ mv src/* .
+$ rmdir src
+
+# Move extra headers into the already-existing internal headers dir
+$ mv *.h include/gtest/internal/
+
+# Update paths to the included files
+$ perl -pi -e 's|^#include "src/|#include "gtest/internal/|' *.cc
+
+$ rm -f gtest-all.cc gtest_main.cc
+
+$ mv COPYING LICENSE.TXT
diff --git a/utils/unittest/googletest/gtest-death-test.cc b/utils/unittest/googletest/gtest-death-test.cc
new file mode 100644
index 000000000000..617e3010f23a
--- /dev/null
+++ b/utils/unittest/googletest/gtest-death-test.cc
@@ -0,0 +1,775 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file implements death tests.
+
+#include <gtest/gtest-death-test.h>
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_HAS_DEATH_TEST
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#endif // GTEST_HAS_DEATH_TEST
+
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION
+#include "gtest/internal/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+ death_test_style,
+ internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+ "Indicates how to run a death test in a forked child process: "
+ "\"threadsafe\" (child process re-executes the test binary "
+ "from the beginning, running only the specific death test) or "
+ "\"fast\" (child process runs the death test immediately "
+ "after forking).");
+
+namespace internal {
+GTEST_DEFINE_string_(
+ internal_run_death_test, "",
+ "Indicates the file, line number, temporal index of "
+ "the single death test to run, and a file descriptor to "
+ "which a success code may be sent, all separated by "
+ "colons. This flag is specified if and only if the current "
+ "process is a sub-process launched for running a thread-safe "
+ "death test. FOR INTERNAL USE ONLY.");
+} // namespace internal
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+}
+
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static String ExitSummary(int exit_code) {
+ Message m;
+ if (WIFEXITED(exit_code)) {
+ m << "Exited with exit status " << WEXITSTATUS(exit_code);
+ } else if (WIFSIGNALED(exit_code)) {
+ m << "Terminated by signal " << WTERMSIG(exit_code);
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(exit_code)) {
+ m << " (core dumped)";
+ }
+#endif
+ return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+ return !ExitedWithCode(0)(exit_status);
+}
+
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement. It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static String DeathTestThreadWarning(size_t thread_count) {
+ Message msg;
+ msg << "Death tests use fork(), which is unsafe particularly"
+ << " in a threaded context. For this test, " << GTEST_NAME << " ";
+ if (thread_count == 0)
+ msg << "couldn't detect the number of threads.";
+ else
+ msg << "detected " << thread_count << " threads.";
+ return msg.GetString();
+}
+
+// Static string containing a description of the outcome of the
+// last death test.
+static String last_death_test_message;
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test
+// can conclude. DIED means that the process died while executing the
+// test code; LIVED means that process lived beyond the end of the test
+// code; and RETURNED means that the test statement attempted a "return,"
+// which is not allowed. IN_PROGRESS means the test has not yet
+// concluded.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the the error
+// message is propagated back to the parent process. Otherwise, the
+// message is simply printed to stderr. In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const char* format, ...) {
+ // This function may be called from a threadsafe-style death test
+ // child process, which operates on a very small stack. Use the
+ // heap for any additional non-miniscule memory requirements.
+ const InternalRunDeathTestFlag* const flag =
+ GetUnitTestImpl()->internal_run_death_test_flag();
+ va_list args;
+ va_start(args, format);
+
+ if (flag != NULL) {
+ FILE* parent = fdopen(flag->status_fd, "w");
+ fputc(kDeathTestInternalError, parent);
+ vfprintf(parent, format, args);
+ fclose(parent);
+ va_end(args);
+ _exit(1);
+ } else {
+ vfprintf(stderr, format, args);
+ va_end(args);
+ abort();
+ }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+#define GTEST_DEATH_TEST_CHECK_(expression) \
+ do { \
+ if (!(expression)) { \
+ DeathTestAbort("CHECK failed: File %s, line %d: %s", \
+ __FILE__, __LINE__, #expression); \
+ } \
+ } while (0)
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again. The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR. If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+ do { \
+ int retval; \
+ do { \
+ retval = (expression); \
+ } while (retval == -1 && errno == EINTR); \
+ if (retval == -1) { \
+ DeathTestAbort("CHECK failed: File %s, line %d: %s != -1", \
+ __FILE__, __LINE__, #expression); \
+ } \
+ } while (0)
+
+// Death test constructor. Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+ TestInfo* const info = GetUnitTestImpl()->current_test_info();
+ if (info == NULL) {
+ DeathTestAbort("Cannot run a death test outside of a TEST or "
+ "TEST_F construct");
+ }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) {
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+ return last_death_test_message.c_str();
+}
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface. Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTest {
+ public:
+ ForkingDeathTest(const char* statement, const RE* regex);
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual bool Passed(bool status_ok);
+ virtual void Abort(AbortReason reason);
+
+ protected:
+ void set_forked(bool forked) { forked_ = forked; }
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+ void set_read_fd(int fd) { read_fd_ = fd; }
+ void set_write_fd(int fd) { write_fd_ = fd; }
+
+ private:
+ // The textual content of the code this object is testing.
+ const char* const statement_;
+ // The regular expression which test output must match.
+ const RE* const regex_;
+ // True if the death test successfully forked.
+ bool forked_;
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+ // File descriptors for communicating the death test's status byte.
+ int read_fd_; // Always -1 in the child process.
+ int write_fd_; // Always -1 in the parent process.
+ // The exit status of the child process.
+ int status_;
+ // How the death test concluded.
+ DeathTestOutcome outcome_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex)
+ : DeathTest(),
+ statement_(statement),
+ regex_(regex),
+ forked_(false),
+ child_pid_(-1),
+ read_fd_(-1),
+ write_fd_(-1),
+ status_(-1),
+ outcome_(IN_PROGRESS) {
+}
+
+// Reads an internal failure message from a file descriptor, then calls
+// LOG(FATAL) with that message. Called from a death test parent process
+// to read a failure message from the death test child process.
+static void FailFromInternalError(int fd) {
+ Message error;
+ char buffer[256];
+ ssize_t num_read;
+
+ do {
+ while ((num_read = read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ // TODO(smcafee): Maybe just FAIL the test instead?
+ if (num_read == 0) {
+ GTEST_LOG_(FATAL, error);
+ } else {
+ GTEST_LOG_(FATAL,
+ Message() << "Error while reading death test internal: "
+ << strerror(errno) << " [" << errno << "]");
+ }
+}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+ if (!forked_)
+ return 0;
+
+ // The read() here blocks until data is available (signifying the
+ // failure of the death test) or until the pipe is closed (signifying
+ // its success), so it's okay to call this in the parent before
+ // the child process has exited.
+ char flag;
+ ssize_t bytes_read;
+
+ do {
+ bytes_read = read(read_fd_, &flag, 1);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0) {
+ outcome_ = DIED;
+ } else if (bytes_read == 1) {
+ switch (flag) {
+ case kDeathTestReturned:
+ outcome_ = RETURNED;
+ break;
+ case kDeathTestLived:
+ outcome_ = LIVED;
+ break;
+ case kDeathTestInternalError:
+ FailFromInternalError(read_fd_); // Does not return.
+ break;
+ default:
+ GTEST_LOG_(FATAL,
+ Message() << "Death test child process reported unexpected "
+ << "status byte (" << static_cast<unsigned int>(flag)
+ << ")");
+ }
+ } else {
+ GTEST_LOG_(FATAL,
+ Message() << "Read from death test child process failed: "
+ << strerror(errno));
+ }
+
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_, 0));
+ return status_;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+// outcome: an enumeration describing how the death test
+// concluded: DIED, LIVED, or RETURNED. The death test fails
+// in the latter two cases
+// status: the exit status of the child process, in the format
+// specified by wait(2)
+// regex: a regular expression object to be applied to
+// the test's captured standard error output; the death test
+// fails if it does not match
+//
+// Argument:
+// status_ok: true if exit_status is acceptable in the context of
+// this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met. Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the static variable last_death_test_message.
+bool ForkingDeathTest::Passed(bool status_ok) {
+ if (!forked_)
+ return false;
+
+#if GTEST_HAS_GLOBAL_STRING
+ const ::string error_message = GetCapturedStderr();
+#else
+ const ::std::string error_message = GetCapturedStderr();
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ bool success = false;
+ Message buffer;
+
+ buffer << "Death test: " << statement_ << "\n";
+ switch (outcome_) {
+ case LIVED:
+ buffer << " Result: failed to die.\n"
+ << " Error msg: " << error_message;
+ break;
+ case RETURNED:
+ buffer << " Result: illegal return in test statement.\n"
+ << " Error msg: " << error_message;
+ break;
+ case DIED:
+ if (status_ok) {
+ if (RE::PartialMatch(error_message, *regex_)) {
+ success = true;
+ } else {
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << regex_->pattern() << "\n"
+ << "Actual msg: " << error_message;
+ }
+ } else {
+ buffer << " Result: died but not with expected exit code:\n"
+ << " " << ExitSummary(status_) << "\n";
+ }
+ break;
+ case IN_PROGRESS:
+ default:
+ GTEST_LOG_(FATAL,
+ "DeathTest::Passed somehow called before conclusion of test");
+ }
+
+ last_death_test_message = buffer.GetString();
+ return success;
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file desriptor, then
+// calls _exit(1).
+void ForkingDeathTest::Abort(AbortReason reason) {
+ // The parent process considers the death test to be a failure if
+ // it finds any data in our pipe. So, here we write a single flag byte
+ // to the pipe, then exit.
+ const char flag =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd_, &flag, 1));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd_));
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+ NoExecDeathTest(const char* statement, const RE* regex) :
+ ForkingDeathTest(statement, regex) { }
+ virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test. It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+ const size_t thread_count = GetThreadCount();
+ if (thread_count != 1) {
+ GTEST_LOG_(WARNING, DeathTestThreadWarning(thread_count));
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+ last_death_test_message = "";
+ CaptureStderr();
+ // When we fork the process below, the log file buffers are copied, but the
+ // file descriptors are shared. We flush all log files here so that closing
+ // the file descriptors in the child process doesn't throw off the
+ // synchronization between descriptors and buffers in the parent process.
+ // This is as close to the fork as possible to avoid a race condition in case
+ // there are multiple threads running before the death test, and another
+ // thread writes to the log file.
+ FlushInfoLog();
+
+ const pid_t child_pid = fork();
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ set_child_pid(child_pid);
+ if (child_pid == 0) {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+ set_write_fd(pipe_fd[1]);
+ // Redirects all logging to stderr in the child process to prevent
+ // concurrent writes to the log files. We capture stderr in the parent
+ // process and append the child process' output to a log.
+ LogToStderr();
+ return EXECUTE_TEST;
+ } else {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_read_fd(pipe_fd[0]);
+ set_forked(true);
+ return OVERSEE_TEST;
+ }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+ ExecDeathTest(const char* statement, const RE* regex,
+ const char* file, int line) :
+ ForkingDeathTest(statement, regex), file_(file), line_(line) { }
+ virtual TestRole AssumeRole();
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() {
+ args_.push_back(NULL);
+ }
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin();
+ i + 1 != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, strdup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, strdup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+ private:
+ std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+ char* const* argv; // Command-line arguments for the child's call to exec
+ int close_fd; // File descriptor to close; the read end of a pipe
+};
+
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+ ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort("chdir(\"%s\") failed: %s",
+ original_dir, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execve() as it's a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // unsafe. Since execve() doesn't search the PATH, the user must
+ // invoke the test program via a valid path that contains at least
+ // one path separator.
+ execve(args->argv[0], args->argv, environ);
+ DeathTestAbort("execve(%s, ...) in %s failed: %s",
+ args->argv[0], original_dir, strerror(errno));
+ return EXIT_FAILURE;
+}
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+static bool StackLowerThanAddress(const void* ptr) {
+ int dummy;
+ return &dummy < ptr;
+}
+
+static bool StackGrowsDown() {
+ int dummy;
+ return StackLowerThanAddress(&dummy);
+}
+
+// A threadsafe implementation of fork(2) for threadsafe-style death tests
+// that uses clone(2). It dies with an error message if anything goes
+// wrong.
+static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const size_t stack_size = getpagesize();
+ void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+ void* const stack_top =
+ static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
+ ExecDeathTestArgs args = { argv, close_fd };
+ const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top,
+ SIGCHLD, &args);
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+ return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test. It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ set_write_fd(flag->status_fd);
+ return EXECUTE_TEST;
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+ // Clear the close-on-exec flag on the write end of the pipe, lest
+ // it be closed when the child process does an exec:
+ GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+ const String filter_flag =
+ String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX, kFilterFlag,
+ info->test_case_name(), info->name());
+ const String internal_flag =
+ String::Format("--%s%s=%s:%d:%d:%d",
+ GTEST_FLAG_PREFIX, kInternalRunDeathTestFlag, file_, line_,
+ death_test_index, pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvs());
+ args.AddArgument("--logtostderr");
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ last_death_test_message = "";
+
+ CaptureStderr();
+ // See the comment in NoExecDeathTest::AssumeRole for why the next line
+ // is necessary.
+ FlushInfoLog();
+
+ const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_child_pid(child_pid);
+ set_read_fd(pipe_fd[0]);
+ set_forked(true);
+ return OVERSEE_TEST;
+}
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address. If the test should be
+// skipped, sets that pointer to NULL. Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+ const char* file, int line,
+ DeathTest** test) {
+ UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const int death_test_index = impl->current_test_info()
+ ->increment_death_test_count();
+
+ if (flag != NULL) {
+ if (death_test_index > flag->index) {
+ last_death_test_message = String::Format(
+ "Death test count (%d) somehow exceeded expected maximum (%d)",
+ death_test_index, flag->index);
+ return false;
+ }
+
+ if (!(flag->file == file && flag->line == line &&
+ flag->index == death_test_index)) {
+ *test = NULL;
+ return true;
+ }
+ }
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, regex, file, line);
+ } else if (GTEST_FLAG(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, regex);
+ } else {
+ last_death_test_message = String::Format(
+ "Unknown death test style \"%s\" encountered",
+ GTEST_FLAG(death_test_style).c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest) {
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (true) {
+ const ::std::string::size_type colon = str.find(delimiter, pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
+// Attempts to parse a string into a positive integer. Returns true
+// if that is possible. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static bool ParsePositiveInt(const ::std::string& str, int* number) {
+ // Fail fast if the given string does not begin with a digit;
+ // this bypasses strtol's "optional leading whitespace and plus
+ // or minus sign" semantics, which are undesirable here.
+ if (str.empty() || !isdigit(str[0])) {
+ return false;
+ }
+ char* endptr;
+ const long parsed = strtol(str.c_str(), &endptr, 10); // NOLINT
+ if (*endptr == '\0' && parsed <= INT_MAX) {
+ *number = static_cast<int>(parsed);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+ if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+ InternalRunDeathTestFlag* const internal_run_death_test_flag =
+ new InternalRunDeathTestFlag;
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ ::std::vector< ::std::string> fields;
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), ':', &fields);
+ if (fields.size() != 4
+ || !ParsePositiveInt(fields[1], &internal_run_death_test_flag->line)
+ || !ParsePositiveInt(fields[2], &internal_run_death_test_flag->index)
+ || !ParsePositiveInt(fields[3],
+ &internal_run_death_test_flag->status_fd)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str());
+ }
+ internal_run_death_test_flag->file = fields[0].c_str();
+ return internal_run_death_test_flag;
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
diff --git a/utils/unittest/googletest/gtest-filepath.cc b/utils/unittest/googletest/gtest-filepath.cc
new file mode 100644
index 000000000000..640c27c313c3
--- /dev/null
+++ b/utils/unittest/googletest/gtest-filepath.cc
@@ -0,0 +1,321 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-port.h>
+
+#include <stdlib.h>
+
+#ifdef _WIN32_WCE
+#include <windows.h>
+#elif defined(GTEST_OS_WINDOWS)
+#include <direct.h>
+#include <io.h>
+#include <sys/stat.h>
+#elif defined(GTEST_OS_SYMBIAN)
+// Symbian OpenC has PATH_MAX in sys/syslimits.h
+#include <sys/syslimits.h>
+#include <unistd.h>
+#else
+#include <limits.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif // _WIN32_WCE or _WIN32
+
+#ifdef GTEST_OS_WINDOWS
+#define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+#define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+#define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif // GTEST_OS_WINDOWS
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+#ifdef GTEST_OS_WINDOWS
+const char kPathSeparator = '\\';
+const char kPathSeparatorString[] = "\\";
+#ifdef _WIN32_WCE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+#else
+const char kCurrentDirectoryString[] = ".\\";
+#endif // _WIN32_WCE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif // GTEST_OS_WINDOWS
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#ifdef _WIN32_WCE
+// Windows CE doesn't have a current directory, so we just return
+// something reasonable.
+ return FilePath(kCurrentDirectoryString);
+#elif defined(GTEST_OS_WINDOWS)
+ char cwd[GTEST_PATH_MAX_ + 1] = {};
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+ char cwd[GTEST_PATH_MAX_ + 1] = {};
+ return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+ String dot_extension(String::Format(".%s", extension));
+ if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
+ return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4));
+ }
+ return *this;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+ return last_sep ? FilePath(String(last_sep + 1)) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+ return FilePath(last_sep ? String(c_str(), last_sep + 1 - c_str())
+ : String(kCurrentDirectoryString));
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension) {
+ FilePath dir(directory.RemoveTrailingPathSeparator());
+ if (number == 0) {
+ return FilePath(String::Format("%s%c%s.%s", dir.c_str(), kPathSeparator,
+ base_name.c_str(), extension));
+ }
+ return FilePath(String::Format("%s%c%s_%d.%s", dir.c_str(), kPathSeparator,
+ base_name.c_str(), number, extension));
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#ifdef GTEST_OS_WINDOWS
+#ifdef _WIN32_WCE
+ LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ return attributes != kInvalidFileAttributes;
+#else
+ struct _stat file_stat = {};
+ return _stat(pathname_.c_str(), &file_stat) == 0;
+#endif // _WIN32_WCE
+#else
+ struct stat file_stat = {};
+ return stat(pathname_.c_str(), &file_stat) == 0;
+#endif // GTEST_OS_WINDOWS
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+ bool result = false;
+#ifdef GTEST_OS_WINDOWS
+ // Don't strip off trailing separator if path is a root directory on
+ // Windows (like "C:\\").
+ const FilePath& path(IsRootDirectory() ? *this :
+ RemoveTrailingPathSeparator());
+#ifdef _WIN32_WCE
+ LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ if ((attributes != kInvalidFileAttributes) &&
+ (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = true;
+ }
+#else
+ struct _stat file_stat = {};
+ result = _stat(path.c_str(), &file_stat) == 0 &&
+ (_S_IFDIR & file_stat.st_mode) != 0;
+#endif // _WIN32_WCE
+#else
+ struct stat file_stat = {};
+ result = stat(pathname_.c_str(), &file_stat) == 0 &&
+ S_ISDIR(file_stat.st_mode);
+#endif // GTEST_OS_WINDOWS
+ return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#ifdef GTEST_OS_WINDOWS
+ const char* const name = pathname_.c_str();
+ return pathname_.GetLength() == 3 &&
+ ((name[0] >= 'a' && name[0] <= 'z') ||
+ (name[0] >= 'A' && name[0] <= 'Z')) &&
+ name[1] == ':' &&
+ name[2] == kPathSeparator;
+#else
+ return pathname_ == kPathSeparatorString;
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension) {
+ FilePath full_pathname;
+ int number = 0;
+ do {
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+ } while (full_pathname.FileOrDirectoryExists());
+ return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+ return pathname_.EndsWith(kPathSeparatorString);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+ if (!this->IsDirectory()) {
+ return false;
+ }
+
+ if (pathname_.GetLength() == 0 || this->DirectoryExists()) {
+ return true;
+ }
+
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#ifdef GTEST_OS_WINDOWS
+#ifdef _WIN32_WCE
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
+ LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+ int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+ delete [] unicode;
+#else
+ int result = _mkdir(pathname_.c_str());
+#endif // !WIN32_WCE
+#else
+ int result = mkdir(pathname_.c_str(), 0777);
+#endif // _WIN32
+ if (result == -1) {
+ return this->DirectoryExists(); // An error is OK if the directory exists.
+ }
+ return true; // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+ return pathname_.EndsWith(kPathSeparatorString)
+ ? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1))
+ : *this;
+}
+
+// Normalize removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+void FilePath::Normalize() {
+ if (pathname_.c_str() == NULL) {
+ pathname_ = "";
+ return;
+ }
+ const char* src = pathname_.c_str();
+ char* const dest = new char[pathname_.GetLength() + 1];
+ char* dest_ptr = dest;
+ memset(dest_ptr, 0, pathname_.GetLength() + 1);
+
+ while (*src != '\0') {
+ *dest_ptr++ = *src;
+ if (*src != kPathSeparator)
+ src++;
+ else
+ while (*src == kPathSeparator)
+ src++;
+ }
+ *dest_ptr = '\0';
+ pathname_ = dest;
+ delete[] dest;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/utils/unittest/googletest/gtest-port.cc b/utils/unittest/googletest/gtest-port.cc
new file mode 100644
index 000000000000..9878cae05d6e
--- /dev/null
+++ b/utils/unittest/googletest/gtest-port.cc
@@ -0,0 +1,332 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/internal/gtest-port.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef GTEST_HAS_DEATH_TEST
+#include <regex.h>
+#endif // GTEST_HAS_DEATH_TEST
+
+#ifdef _WIN32_WCE
+#include <windows.h> // For TerminateProcess()
+#endif // _WIN32_WCE
+
+#include <gtest/gtest-spi.h>
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+
+namespace testing {
+namespace internal {
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// Implements RE. Currently only needed for death tests.
+
+RE::~RE() {
+ regfree(&partial_regex_);
+ regfree(&full_regex_);
+ free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = strdup(regex);
+
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match.
+ const size_t full_regex_len = strlen(regex) + 10;
+ char* const full_pattern = new char[full_regex_len];
+
+ snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+ is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+ // We want to call regcomp(&partial_regex_, ...) even if the
+ // previous expression returns false. Otherwise partial_regex_ may
+ // not be properly initialized can may cause trouble when it's
+ // freed.
+ is_valid_ = (regcomp(&partial_regex_, regex, REG_EXTENDED) == 0) && is_valid_;
+ EXPECT_TRUE(is_valid_)
+ << "Regular expression \"" << regex
+ << "\" is not a valid POSIX Extended regular expression.";
+
+ delete[] full_pattern;
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Logs a message at the given severity level.
+void GTestLog(GTestLogSeverity severity, const char* file,
+ int line, const char* msg) {
+ const char* const marker =
+ severity == GTEST_INFO ? "[ INFO ]" :
+ severity == GTEST_WARNING ? "[WARNING]" :
+ severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
+ fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);
+ if (severity == GTEST_FATAL) {
+ abort();
+ }
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// Defines the stderr capturer.
+
+class CapturedStderr {
+ public:
+ // The ctor redirects stderr to a temporary file.
+ CapturedStderr() {
+ uncaptured_fd_ = dup(STDERR_FILENO);
+
+ // There's no guarantee that a test has write access to the
+ // current directory, so we create the temporary file in the /tmp
+ // directory instead.
+ char name_template[] = "/tmp/captured_stderr.XXXXXX";
+ const int captured_fd = mkstemp(name_template);
+ filename_ = name_template;
+ fflush(NULL);
+ dup2(captured_fd, STDERR_FILENO);
+ close(captured_fd);
+ }
+
+ ~CapturedStderr() {
+ remove(filename_.c_str());
+ }
+
+ // Stops redirecting stderr.
+ void StopCapture() {
+ // Restores the original stream.
+ fflush(NULL);
+ dup2(uncaptured_fd_, STDERR_FILENO);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ // Returns the name of the temporary file holding the stderr output.
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ ::std::string filename() const { return filename_; }
+
+ private:
+ int uncaptured_fd_;
+ ::std::string filename_;
+};
+
+static CapturedStderr* g_captured_stderr = NULL;
+
+// Returns the size (in bytes) of a file.
+static size_t GetFileSize(FILE * file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
+// use it here.
+static ::std::string ReadEntireFile(FILE * file) {
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const ::std::string content(buffer, buffer+bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+ if (g_captured_stderr != NULL) {
+ GTEST_LOG_(FATAL, "Only one stderr capturer can exist at one time.");
+ }
+ g_captured_stderr = new CapturedStderr;
+}
+
+// Stops capturing stderr and returns the captured string.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
+// use it here.
+::std::string GetCapturedStderr() {
+ g_captured_stderr->StopCapture();
+ FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r");
+ const ::std::string content = ReadEntireFile(file);
+ fclose(file);
+
+ delete g_captured_stderr;
+ g_captured_stderr = NULL;
+
+ return content;
+}
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+::std::vector<String> g_argvs;
+
+// Returns the command line as a vector of strings.
+const ::std::vector<String>& GetArgvs() { return g_argvs; }
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#ifdef _WIN32_WCE
+void abort() {
+ DebugBreak();
+ TerminateProcess(GetCurrentProcess(), 1);
+}
+#endif // _WIN32_WCE
+
+// Returns the name of the environment variable corresponding to the
+// given flag. For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static String FlagToEnvVar(const char* flag) {
+ const String full_flag = (Message() << GTEST_FLAG_PREFIX << flag).GetString();
+
+ Message env_var;
+ for (int i = 0; i != full_flag.GetLength(); i++) {
+ env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
+ }
+
+ return env_var.GetString();
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = GetEnv(env_var.c_str());
+ return string_value == NULL ?
+ default_value : strcmp(string_value, "0") != 0;
+}
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+ // Parses the environment variable as a decimal integer.
+ char* end = NULL;
+ const long long_value = strtol(str, &end, 10); // NOLINT
+
+ // Has strtol() consumed all characters in the string?
+ if (*end != '\0') {
+ // No - an invalid character was encountered.
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value \"" << str << "\".\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ // Is the parsed value in the range of an Int32?
+ const Int32 result = static_cast<Int32>(long_value);
+ if (long_value == LONG_MAX || long_value == LONG_MIN ||
+ // The parsed value overflows as a long. (strtol() returns
+ // LONG_MAX or LONG_MIN when the input overflows.)
+ result != long_value
+ // The parsed value overflows as an Int32.
+ ) {
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value " << str << ", which overflows.\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ *value = result;
+ return true;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = GetEnv(env_var.c_str());
+ if (string_value == NULL) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ Int32 result = default_value;
+ if (!ParseInt32(Message() << "Environment variable " << env_var,
+ string_value, &result)) {
+ printf("The default value %s is used.\n",
+ (Message() << default_value).GetString().c_str());
+ fflush(stdout);
+ return default_value;
+ }
+
+ return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const value = GetEnv(env_var.c_str());
+ return value == NULL ? default_value : value;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/utils/unittest/googletest/gtest-test-part.cc b/utils/unittest/googletest/gtest-test-part.cc
new file mode 100644
index 000000000000..2e80f21d3835
--- /dev/null
+++ b/utils/unittest/googletest/gtest-test-part.cc
@@ -0,0 +1,124 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest-test-part.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION
+#include "gtest/internal/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION
+
+namespace testing {
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+internal::String TestPartResult::ExtractSummary(const char* message) {
+ const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+ return stack_trace == NULL ? internal::String(message) :
+ internal::String(message, stack_trace - message);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+ return os << result.file_name() << ":"
+ << result.line_number() << ": "
+ << (result.type() == TPRT_SUCCESS ? "Success" :
+ result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" :
+ "Non-fatal failure") << ":\n"
+ << result.message() << std::endl;
+}
+
+// Constructs an empty TestPartResultArray.
+TestPartResultArray::TestPartResultArray()
+ : list_(new internal::List<TestPartResult>) {
+}
+
+// Destructs a TestPartResultArray.
+TestPartResultArray::~TestPartResultArray() {
+ delete list_;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+ list_->PushBack(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+ if (index < 0 || index >= size()) {
+ printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+ internal::abort();
+ }
+
+ const internal::ListNode<TestPartResult>* p = list_->Head();
+ for (int i = 0; i < index; i++) {
+ p = p->next();
+ }
+
+ return p->element();
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+ return list_->size();
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+ : has_new_fatal_failure_(false),
+ original_reporter_(UnitTest::GetInstance()->impl()->
+ GetTestPartResultReporterForCurrentThread()) {
+ UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread(
+ this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+ UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread(
+ original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+ const TestPartResult& result) {
+ if (result.fatally_failed())
+ has_new_fatal_failure_ = true;
+ original_reporter_->ReportTestPartResult(result);
+}
+
+} // namespace internal
+
+} // namespace testing
diff --git a/utils/unittest/googletest/gtest-typed-test.cc b/utils/unittest/googletest/gtest-typed-test.cc
new file mode 100644
index 000000000000..d42a1596d570
--- /dev/null
+++ b/utils/unittest/googletest/gtest-typed-test.cc
@@ -0,0 +1,97 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest-typed-test.h>
+#include <gtest/gtest.h>
+
+namespace testing {
+namespace internal {
+
+#ifdef GTEST_HAS_TYPED_TEST_P
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests) {
+ typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+ registered_ = true;
+
+ Message errors;
+ ::std::set<String> tests;
+ for (const char* names = registered_tests; names != NULL;
+ names = SkipComma(names)) {
+ const String name = GetPrefixUntilComma(names);
+ if (tests.count(name) != 0) {
+ errors << "Test " << name << " is listed more than once.\n";
+ continue;
+ }
+
+ bool found = false;
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (name == *it) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ tests.insert(name);
+ } else {
+ errors << "No test named " << name
+ << " can be found in this test case.\n";
+ }
+ }
+
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (tests.count(*it) == 0) {
+ errors << "You forgot to list test " << *it << ".\n";
+ }
+ }
+
+ const String& errors_str = errors.GetString();
+ if (errors_str != "") {
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors_str.c_str());
+ abort();
+ }
+
+ return registered_tests;
+}
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing
diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc
new file mode 100644
index 000000000000..e46e90a2c47c
--- /dev/null
+++ b/utils/unittest/googletest/gtest.cc
@@ -0,0 +1,3951 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#ifdef GTEST_OS_LINUX
+
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+#define GTEST_HAS_GETTIMEOFDAY
+
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+// Declares vsnprintf(). This header is not available on Windows.
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#elif defined(GTEST_OS_SYMBIAN)
+#define GTEST_HAS_GETTIMEOFDAY
+#include <sys/time.h> // NOLINT
+
+#elif defined(GTEST_OS_ZOS)
+#define GTEST_HAS_GETTIMEOFDAY
+#include <sys/time.h> // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+#include <strings.h>
+
+#elif defined(_WIN32_WCE) // We are on Windows CE.
+
+#include <windows.h> // NOLINT
+
+#elif defined(GTEST_OS_WINDOWS) // We are on Windows proper.
+
+#include <io.h> // NOLINT
+#include <sys/timeb.h> // NOLINT
+#include <sys/types.h> // NOLINT
+#include <sys/stat.h> // NOLINT
+
+#if defined(__MINGW__) || defined(__MINGW32__)
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+// TODO(kenton@google.com): There are other ways to get the time on
+// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW
+// supports these. consider using them instead.
+#define GTEST_HAS_GETTIMEOFDAY
+#include <sys/time.h> // NOLINT
+#endif
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <windows.h> // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+#define GTEST_HAS_GETTIMEOFDAY
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <sys/time.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION
+#include "gtest/internal/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION
+
+#ifdef GTEST_OS_WINDOWS
+#define fileno _fileno
+#define isatty _isatty
+#define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+namespace testing {
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+} // namespace internal
+
+GTEST_DEFINE_bool_(
+ break_on_failure,
+ internal::BoolFromGTestEnv("break_on_failure", false),
+ "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+ catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", false),
+ "True iff " GTEST_NAME
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+ color,
+ internal::StringFromGTestEnv("color", "auto"),
+ "Whether to use colors in the output. Valid values: yes, no, "
+ "and auto. 'auto' means to use colors if the output is "
+ "being sent to a terminal and the TERM environment variable "
+ "is set to xterm or xterm-color.");
+
+GTEST_DEFINE_string_(
+ filter,
+ internal::StringFromGTestEnv("filter", kUniversalFilter),
+ "A colon-separated list of glob (not regex) patterns "
+ "for filtering the tests to run, optionally followed by a "
+ "'-' and a : separated list of negative patterns (tests to "
+ "exclude). A test is run if it matches one of the positive "
+ "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+ "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+ output,
+ internal::StringFromGTestEnv("output", ""),
+ "A format (currently must be \"xml\"), optionally followed "
+ "by a colon and an output file name or directory. A directory "
+ "is indicated by a trailing pathname separator. "
+ "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+ "If a directory is specified, output files will be created "
+ "within that directory, with file-names based on the test "
+ "executable's name and, if necessary, made unique by adding "
+ "digits.");
+
+GTEST_DEFINE_bool_(
+ print_time,
+ internal::BoolFromGTestEnv("print_time", false),
+ "True iff " GTEST_NAME
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+ repeat,
+ internal::Int32FromGTestEnv("repeat", 1),
+ "How many times to repeat each test. Specify a negative number "
+ "for repeating forever. Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_int32_(
+ stack_trace_depth,
+ internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+ "The maximum number of stack frames to print when an "
+ "assertion fails. The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_bool_(
+ show_internal_stack_frames, false,
+ "True iff " GTEST_NAME " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+namespace internal {
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test. g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called. We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a list of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const internal::List<TestCase*>& case_list,
+ int (TestCase::*method)() const) {
+ int sum = 0;
+ for (const internal::ListNode<TestCase*>* node = case_list.Head();
+ node != NULL;
+ node = node->next()) {
+ sum += (node->element()->*method)();
+ }
+ return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+ return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResultType type, const char* file,
+ int line, const char* message)
+ : type_(type), file_(file), line_(line), message_(message) {
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+ UnitTest::GetInstance()->
+ AddTestPartResult(type_, file_, line_,
+ AppendUserMessage(message_, message),
+ UnitTest::GetInstance()->impl()
+ ->CurrentOsStackTraceExceptTop(1)
+ // Skips the stack frame for this function itself.
+ ); // NOLINT
+}
+
+// Mutex for linked pointers.
+Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
+
+// Application pathname gotten in InitGoogleTest.
+String g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+ FilePath result;
+
+#if defined(_WIN32_WCE) || defined(GTEST_OS_WINDOWS)
+ result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(g_executable_path));
+#endif // _WIN32_WCE || GTEST_OS_WINDOWS
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+String UnitTestOptions::GetOutputFormat() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL) return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == NULL) ?
+ String(gtest_output_flag) :
+ String(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+String UnitTestOptions::GetOutputFile() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL)
+ return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == NULL)
+ return String(kDefaultOutputFile);
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsDirectory())
+ return output_name.ToString();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.ToString();
+}
+
+// Returns true iff the wildcard pattern matches the string. The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+ const char *str) {
+ switch (*pattern) {
+ case '\0':
+ case ':': // Either ':' or '\0' marks the end of the pattern.
+ return *str == '\0';
+ case '?': // Matches any single character.
+ return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+ case '*': // Matches any string (possibly empty) of characters.
+ return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+ PatternMatchesString(pattern + 1, str);
+ default: // Non-special character. Matches itself.
+ return *pattern == *str &&
+ PatternMatchesString(pattern + 1, str + 1);
+ }
+}
+
+bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {
+ const char *cur_pattern = filter;
+ while (true) {
+ if (PatternMatchesString(cur_pattern, name.c_str())) {
+ return true;
+ }
+
+ // Finds the next pattern in the filter.
+ cur_pattern = strchr(cur_pattern, ':');
+
+ // Returns if no more pattern can be found.
+ if (cur_pattern == NULL) {
+ return false;
+ }
+
+ // Skips the pattern separater (the ':' character).
+ cur_pattern++;
+ }
+}
+
+// TODO(keithray): move String function implementations to gtest-string.cc.
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
+ const String &test_name) {
+ const String& full_name = String::Format("%s.%s",
+ test_case_name.c_str(),
+ test_name.c_str());
+
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ const char* const p = GTEST_FLAG(filter).c_str();
+ const char* const dash = strchr(p, '-');
+ String positive;
+ String negative;
+ if (dash == NULL) {
+ positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
+ negative = String("");
+ } else {
+ positive.Set(p, dash - p); // Everything up to the dash
+ negative = String(dash+1); // Everything after the dash
+ if (positive.empty()) {
+ // Treat '-test1' as the same as '*-test1'
+ positive = kUniversalFilter;
+ }
+ }
+
+ // A filter is a colon-separated list of patterns. It matches a
+ // test if any pattern in it matches the test.
+ return (MatchesFilter(full_name, positive.c_str()) &&
+ !MatchesFilter(full_name, negative.c_str()));
+}
+
+#ifdef GTEST_OS_WINDOWS
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+ // Google Test should handle an exception if:
+ // 1. the user wants it to, AND
+ // 2. this is not a breakpoint exception.
+ return (GTEST_FLAG(catch_exceptions) &&
+ exception_code != EXCEPTION_BREAKPOINT) ?
+ EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // GTEST_OS_WINDOWS
+
+} // namespace internal
+
+// The interface for printing the result of a UnitTest
+class UnitTestEventListenerInterface {
+ public:
+ // The d'tor is pure virtual as this is an abstract class.
+ virtual ~UnitTestEventListenerInterface() = 0;
+
+ // Called before the unit test starts.
+ virtual void OnUnitTestStart(const UnitTest*) {}
+
+ // Called after the unit test ends.
+ virtual void OnUnitTestEnd(const UnitTest*) {}
+
+ // Called before the test case starts.
+ virtual void OnTestCaseStart(const TestCase*) {}
+
+ // Called after the test case ends.
+ virtual void OnTestCaseEnd(const TestCase*) {}
+
+ // Called before the global set-up starts.
+ virtual void OnGlobalSetUpStart(const UnitTest*) {}
+
+ // Called after the global set-up ends.
+ virtual void OnGlobalSetUpEnd(const UnitTest*) {}
+
+ // Called before the global tear-down starts.
+ virtual void OnGlobalTearDownStart(const UnitTest*) {}
+
+ // Called after the global tear-down ends.
+ virtual void OnGlobalTearDownEnd(const UnitTest*) {}
+
+ // Called before the test starts.
+ virtual void OnTestStart(const TestInfo*) {}
+
+ // Called after the test ends.
+ virtual void OnTestEnd(const TestInfo*) {}
+
+ // Called after an assertion.
+ virtual void OnNewTestPartResult(const TestPartResult*) {}
+};
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ TestPartResultArray* result)
+ : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+ result_(result) {
+ Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ InterceptMode intercept_mode, TestPartResultArray* result)
+ : intercept_mode_(intercept_mode),
+ result_(result) {
+ Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+ internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ old_reporter_ = impl->GetGlobalTestPartResultReporter();
+ impl->SetGlobalTestPartResultReporter(this);
+ } else {
+ old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+ impl->SetTestPartResultReporterForCurrentThread(this);
+ }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+ internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ impl->SetGlobalTestPartResultReporter(old_reporter_);
+ } else {
+ impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+ }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test. We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test. This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X. The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code. GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+ return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResultType type,
+ const char* substr) {
+ const String expected(
+ type == TPRT_FATAL_FAILURE ? "1 fatal failure" :
+ "1 non-fatal failure");
+ Message msg;
+ if (results.size() != 1) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual: " << results.size() << " failures";
+ for (int i = 0; i < results.size(); i++) {
+ msg << "\n" << results.GetTestPartResult(i);
+ }
+ return AssertionFailure(msg);
+ }
+
+ const TestPartResult& r = results.GetTestPartResult(0);
+ if (r.type() != type) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual:\n"
+ << r;
+ return AssertionFailure(msg);
+ }
+
+ if (strstr(r.message(), substr) == NULL) {
+ msg << "Expected: " << expected << " containing \""
+ << substr << "\"\n"
+ << " Actual:\n"
+ << r;
+ return AssertionFailure(msg);
+ }
+
+ return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+ const TestPartResultArray* results,
+ TestPartResultType type,
+ const char* substr)
+ : results_(results),
+ type_(type),
+ substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+ EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str());
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->current_test_result()->AddTestPartResult(result);
+ unit_test_->result_printer()->OnNewTestPartResult(&result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter) {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+ return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter) {
+ per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+ return test_cases_.CountIf(TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+ return test_cases_.CountIf(TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+ return test_cases_.size();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+ return test_cases_.CountIf(ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+ (void)skip_count;
+ return String("");
+}
+
+static TimeInMillis GetTimeInMillis() {
+#ifdef _WIN32_WCE // We are on Windows CE
+ // Difference between 1970-01-01 and 1601-01-01 in miliseconds.
+ // http://analogous.blogspot.com/2005/04/epoch.html
+ const TimeInMillis kJavaEpochToWinFileTimeDelta = 11644473600000UL;
+ const DWORD kTenthMicrosInMilliSecond = 10000;
+
+ SYSTEMTIME now_systime;
+ FILETIME now_filetime;
+ ULARGE_INTEGER now_int64;
+ // TODO(kenton@google.com): Shouldn't this just use
+ // GetSystemTimeAsFileTime()?
+ GetSystemTime(&now_systime);
+ if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+ now_int64.LowPart = now_filetime.dwLowDateTime;
+ now_int64.HighPart = now_filetime.dwHighDateTime;
+ now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+ kJavaEpochToWinFileTimeDelta;
+ return now_int64.QuadPart;
+ }
+ return 0;
+#elif defined(GTEST_OS_WINDOWS) && !defined(GTEST_HAS_GETTIMEOFDAY)
+ __timeb64 now;
+#ifdef _MSC_VER
+ // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+ // (deprecated function) there.
+ // TODO(kenton@google.com): Use GetTickCount()? Or use
+ // SystemTimeToFileTime()
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ _ftime64(&now);
+#pragma warning(pop) // Restores the warning state.
+#else
+ _ftime64(&now);
+#endif // _MSC_VER
+ return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif defined(GTEST_HAS_GETTIMEOFDAY)
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+#error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String
+
+// Returns the input enclosed in double quotes if it's not NULL;
+// otherwise returns "(null)". For example, "\"Hello\"" is returned
+// for input "Hello".
+//
+// This is useful for printing a C string in the syntax of a literal.
+//
+// Known issue: escape sequences are not handled yet.
+String String::ShowCStringQuoted(const char* c_str) {
+ return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
+}
+
+// Copies at most length characters from str into a newly-allocated
+// piece of memory of size length+1. The memory is allocated with new[].
+// A terminating null byte is written to the memory, and a pointer to it
+// is returned. If str is NULL, NULL is returned.
+static char* CloneString(const char* str, size_t length) {
+ if (str == NULL) {
+ return NULL;
+ } else {
+ char* const clone = new char[length + 1];
+ // MSVC 8 deprecates strncpy(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ strncpy(clone, str, length);
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ strncpy(clone, str, length);
+#endif // GTEST_OS_WINDOWS
+ clone[length] = '\0';
+ return clone;
+ }
+}
+
+// Clones a 0-terminated C string, allocating memory using new. The
+// caller is responsible for deleting[] the return value. Returns the
+// cloned string, or NULL if the input is NULL.
+const char * String::CloneCString(const char* c_str) {
+ return (c_str == NULL) ?
+ NULL : CloneString(c_str, strlen(c_str));
+}
+
+#ifdef _WIN32_WCE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+ if (!ansi) return NULL;
+ const int length = strlen(ansi);
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ NULL, 0);
+ WCHAR* unicode = new WCHAR[unicode_length + 1];
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ unicode, unicode_length);
+ unicode[unicode_length] = 0;
+ return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str) {
+ if (!utf16_str) return NULL;
+ const int ansi_length =
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ NULL, 0, NULL, NULL);
+ char* ansi = new char[ansi_length + 1];
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ ansi, ansi_length, NULL, NULL);
+ ansi[ansi_length] = 0;
+ return ansi;
+}
+
+#endif // _WIN32_WCE
+
+// Compares two C strings. Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len,
+ Message* msg) {
+ // TODO(wan): consider allowing a testing::String object to
+ // contain '\0'. This will make it behave more like std::string,
+ // and will allow ToUtf8String() to return the correct encoding
+ // for '\0' s.t. we can get rid of the conditional here (and in
+ // several other places).
+ for (size_t i = 0; i != len; ) { // NOLINT
+ if (wstr[i] != L'\0') {
+ *msg << WideStringToUtf8(wstr + i, static_cast<int>(len - i));
+ while (i != len && wstr[i] != L'\0')
+ i++;
+ } else {
+ *msg << '\0';
+ i++;
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+} // namespace internal
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+namespace internal {
+
+// Formats a value to be used in a failure message.
+
+// For a char value, we print it as a C++ char literal and as an
+// unsigned integer (both in decimal and in hexadecimal).
+String FormatForFailureMessage(char ch) {
+ const unsigned int ch_as_uint = ch;
+ // A String object cannot contain '\0', so we print "\\0" when ch is
+ // '\0'.
+ return String::Format("'%s' (%u, 0x%X)",
+ ch ? String::Format("%c", ch).c_str() : "\\0",
+ ch_as_uint, ch_as_uint);
+}
+
+// For a wchar_t value, we print it as a C++ wchar_t literal and as an
+// unsigned integer (both in decimal and in hexidecimal).
+String FormatForFailureMessage(wchar_t wchar) {
+ // The C++ standard doesn't specify the exact size of the wchar_t
+ // type. It just says that it shall have the same size as another
+ // integral type, called its underlying type.
+ //
+ // Therefore, in order to print a wchar_t value in the numeric form,
+ // we first convert it to the largest integral type (UInt64) and
+ // then print the converted value.
+ //
+ // We use streaming to print the value as "%llu" doesn't work
+ // correctly with MSVC 7.1.
+ const UInt64 wchar_as_uint64 = wchar;
+ Message msg;
+ // A String object cannot contain '\0', so we print "\\0" when wchar is
+ // L'\0'.
+ char buffer[32]; // CodePointToUtf8 requires a buffer that big.
+ msg << "L'"
+ << (wchar ? CodePointToUtf8(static_cast<UInt32>(wchar), buffer) : "\\0")
+ << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16)
+ << wchar_as_uint64 << ")";
+ return msg.GetString();
+}
+
+} // namespace internal
+
+// AssertionResult constructor.
+AssertionResult::AssertionResult(const internal::String& failure_message)
+ : failure_message_(failure_message) {
+}
+
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+ return AssertionResult();
+}
+
+
+// Makes a failed assertion result with the given failure message.
+AssertionResult AssertionFailure(const Message& message) {
+ return AssertionResult(message.GetString());
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case) {
+ Message msg;
+ msg << "Value of: " << actual_expression;
+ if (actual_value != actual_expression) {
+ msg << "\n Actual: " << actual_value;
+ }
+
+ msg << "\nExpected: " << expected_expression;
+ if (ignoring_case) {
+ msg << " (ignoring case)";
+ }
+ if (expected_value != expected_expression) {
+ msg << "\nWhich is: " << expected_value;
+ }
+
+ return AssertionFailure(msg);
+}
+
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error) {
+ const double diff = fabs(val1 - val2);
+ if (diff <= abs_error) return AssertionSuccess();
+
+ // TODO(wan): do not print the value of an expression if it's
+ // already a literal.
+ Message msg;
+ msg << "The difference between " << expr1 << " and " << expr2
+ << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ", and\n"
+ << abs_error_expr << " evaluates to " << abs_error << ".";
+ return AssertionFailure(msg);
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+ const char* expr2,
+ RawType val1,
+ RawType val2) {
+ // Returns success if val1 is less than val2,
+ if (val1 < val2) {
+ return AssertionSuccess();
+ }
+
+ // or if val1 is almost equal to val2.
+ const FloatingPoint<RawType> lhs(val1), rhs(val2);
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ // Note that the above two checks will both fail if either val1 or
+ // val2 is NaN, as the IEEE floating-point standard requires that
+ // any predicate involving a NaN must return false.
+
+ StrStream val1_ss;
+ val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val1;
+
+ StrStream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val2;
+
+ Message msg;
+ msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+ << " Actual: " << StrStreamToString(&val1_ss) << " vs "
+ << StrStreamToString(&val2_ss);
+
+ return AssertionFailure(msg);
+}
+
+} // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2) {
+ return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2) {
+ return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ Message msg;\
+ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return AssertionFailure(msg);\
+ }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ return AssertionFailure(msg);
+ }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << ") (ignoring case), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ return AssertionFailure(msg);
+ }
+}
+
+} // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack. NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+ const StringType& haystack) {
+ return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+ bool expected_to_be_substring,
+ const char* needle_expr, const char* haystack_expr,
+ const StringType& needle, const StringType& haystack) {
+ if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(needle[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure(
+ Message()
+ << "Value of: " << needle_expr << "\n"
+ << " Actual: " << begin_string_quote << needle << "\"\n"
+ << "Expected: " << (expected_to_be_substring ? "" : "not ")
+ << "a substring of " << haystack_expr << "\n"
+ << "Which is: " << begin_string_quote << haystack << "\"");
+}
+
+} // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_STRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#ifdef GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+ const char* expected,
+ long hr) { // NOLINT
+#ifdef _WIN32_WCE
+ // Windows CE doesn't support FormatMessage.
+ const char error_text[] = "";
+#else
+ // Looks up the human-readable system message for the HRESULT code
+ // and since we're not passing any params to FormatMessage, we don't
+ // want inserts expanded.
+ const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+ const DWORD kBufSize = 4096; // String::Format can't exceed this length.
+ // Gets the system's human readable message string for this HRESULT.
+ char error_text[kBufSize] = { '\0' };
+ DWORD message_length = ::FormatMessageA(kFlags,
+ 0, // no source, we're asking system
+ hr, // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ NULL); // no arguments for inserts
+ // Trims tailing white space (FormatMessage leaves a trailing cr-lf)
+ for (; message_length && isspace(error_text[message_length - 1]);
+ --message_length) {
+ error_text[message_length - 1] = '\0';
+ }
+#endif // _WIN32_WCE
+
+ const String error_hex(String::Format("0x%08X ", hr));
+ Message msg;
+ msg << "Expected: " << expr << " " << expected << ".\n"
+ << " Actual: " << error_hex << error_text << "\n";
+
+ return ::testing::AssertionFailure(msg);
+}
+
+} // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT
+ if (SUCCEEDED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
+ if (FAILED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length Encoding
+// 0 - 7 bits 0xxxxxxx
+// 8 - 11 bits 110xxxxx 10xxxxxx
+// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
+// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern. Returns the n
+// lowest bits. As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+ const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+ *bits >>= n;
+ return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+char* CodePointToUtf8(UInt32 code_point, char* str) {
+ if (code_point <= kMaxCodePoint1) {
+ str[1] = '\0';
+ str[0] = static_cast<char>(code_point); // 0xxxxxxx
+ } else if (code_point <= kMaxCodePoint2) {
+ str[2] = '\0';
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
+ } else if (code_point <= kMaxCodePoint3) {
+ str[3] = '\0';
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
+ } else if (code_point <= kMaxCodePoint4) {
+ str[4] = '\0';
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
+ } else {
+ // The longest string String::Format can produce when invoked
+ // with these parameters is 28 character long (not including
+ // the terminating nul character). We are asking for 32 character
+ // buffer just in case. This is also enough for strncpy to
+ // null-terminate the destination string.
+ // MSVC 8 deprecates strncpy(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+#endif
+ strncpy(str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(),
+ 32);
+#ifdef GTEST_OS_WINDOWS // We are on Windows.
+#pragma warning(pop) // Restores the warning state.
+#endif
+ str[31] = '\0'; // Makes sure no change in the format to strncpy leaves
+ // the result unterminated.
+ }
+ return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+ if (sizeof(wchar_t) == 2)
+ return (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+ else
+ return false;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+ wchar_t second) {
+ if (sizeof(wchar_t) == 2) {
+ const UInt32 mask = (1 << 10) - 1;
+ return (((first & mask) << 10) | (second & mask)) + 0x10000;
+ } else {
+ // This should not be called, but we provide a sensible default
+ // in case it is.
+ return static_cast<UInt32>(first);
+ }
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+String WideStringToUtf8(const wchar_t* str, int num_chars) {
+ if (num_chars == -1)
+ num_chars = static_cast<int>(wcslen(str));
+
+ StrStream stream;
+ for (int i = 0; i < num_chars; ++i) {
+ UInt32 unicode_code_point;
+
+ if (str[i] == L'\0') {
+ break;
+ } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+ unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+ str[i + 1]);
+ i++;
+ } else {
+ unicode_code_point = static_cast<UInt32>(str[i]);
+ }
+
+ char buffer[32]; // CodePointToUtf8 requires a buffer this big.
+ stream << CodePointToUtf8(unicode_code_point, buffer);
+ }
+ return StrStreamToString(&stream);
+}
+
+// Converts a wide C string to a String using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+String String::ShowWideCString(const wchar_t * wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());
+}
+
+// Similar to ShowWideCString(), except that this function encloses
+// the converted string in double quotes.
+String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String::Format("L\"%s\"",
+ String::ShowWideCString(wide_c_str).c_str());
+}
+
+// Compares two wide C strings. Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual) {
+ if (String::WideCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowWideCStringQuoted(expected),
+ String::ShowWideCStringQuoted(actual),
+ false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2) {
+ if (!String::WideCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: "
+ << String::ShowWideCStringQuoted(s1)
+ << " vs " << String::ShowWideCStringQuoted(s2);
+ return AssertionFailure(msg);
+}
+
+// Compares two C strings, ignoring case. Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s). A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+#ifdef GTEST_OS_WINDOWS
+ return _stricmp(lhs, rhs) == 0;
+#else // GTEST_OS_WINDOWS
+ return strcasecmp(lhs, rhs) == 0;
+#endif // GTEST_OS_WINDOWS
+}
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+#ifdef GTEST_OS_WINDOWS
+ return _wcsicmp(lhs, rhs) == 0;
+#elif defined(GTEST_OS_LINUX)
+ return wcscasecmp(lhs, rhs) == 0;
+#else
+ // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes
+ // may not define it either.
+ wint_t left, right;
+ do {
+ left = towlower(*lhs++);
+ right = towlower(*rhs++);
+ } while (left && left == right);
+ return left == right;
+#endif // OS selector
+}
+
+// Constructs a String by copying a given number of chars from a
+// buffer. E.g. String("hello", 3) will create the string "hel".
+String::String(const char * buffer, size_t len) {
+ char * const temp = new char[ len + 1 ];
+ memcpy(temp, buffer, len);
+ temp[ len ] = '\0';
+ c_str_ = temp;
+}
+
+// Compares this with another String.
+// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+// if this is greater than rhs.
+int String::Compare(const String & rhs) const {
+ if ( c_str_ == NULL ) {
+ return rhs.c_str_ == NULL ? 0 : -1; // NULL < anything except NULL
+ }
+
+ return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_);
+}
+
+// Returns true iff this String ends with the given suffix. *Any*
+// String is considered to end with a NULL or empty suffix.
+bool String::EndsWith(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str_ == NULL) return false;
+
+ const size_t this_len = strlen(c_str_);
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CStringEquals(c_str_ + this_len - suffix_len, suffix);
+}
+
+// Returns true iff this String ends with the given suffix, ignoring case.
+// Any String is considered to end with a NULL or empty suffix.
+bool String::EndsWithCaseInsensitive(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str_ == NULL) return false;
+
+ const size_t this_len = strlen(c_str_);
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix);
+}
+
+// Sets the 0-terminated C string this String object represents. The
+// old string in this object is deleted, and this object will own a
+// clone of the input string. This function copies only up to length
+// bytes (plus a terminating null byte), or until the first null byte,
+// whichever comes first.
+//
+// This function works even when the c_str parameter has the same
+// value as that of the c_str_ field.
+void String::Set(const char * c_str, size_t length) {
+ // Makes sure this works when c_str == c_str_
+ const char* const temp = CloneString(c_str, length);
+ delete[] c_str_;
+ c_str_ = temp;
+}
+
+// Assigns a C string to this object. Self-assignment works.
+const String& String::operator=(const char* c_str) {
+ // Makes sure this works when c_str == c_str_
+ if (c_str != c_str_) {
+ delete[] c_str_;
+ c_str_ = CloneCString(c_str);
+ }
+ return *this;
+}
+
+// Formats a list of arguments to a String, using the same format
+// spec string as for printf.
+//
+// We do not use the StringPrintf class as it is not universally
+// available.
+//
+// The result is limited to 4096 characters (including the tailing 0).
+// If 4096 characters are not enough to format the input,
+// "<buffer exceeded>" is returned.
+String String::Format(const char * format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ char buffer[4096];
+ // MSVC 8 deprecates vsnprintf(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ const int size =
+ vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ const int size =
+ vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);
+#endif // GTEST_OS_WINDOWS
+ va_end(args);
+
+ return String(size >= 0 ? buffer : "<buffer exceeded>");
+}
+
+// Converts the buffer in a StrStream to a String, converting NUL
+// bytes to "\\0" along the way.
+String StrStreamToString(StrStream* ss) {
+#if GTEST_HAS_STD_STRING
+ const ::std::string& str = ss->str();
+ const char* const start = str.c_str();
+ const char* const end = start + str.length();
+#else
+ const char* const start = ss->str();
+ const char* const end = start + ss->pcount();
+#endif // GTEST_HAS_STD_STRING
+
+ // We need to use a helper StrStream to do this transformation
+ // because String doesn't support push_back().
+ StrStream helper;
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ helper << "\\0"; // Replaces NUL with "\\0";
+ } else {
+ helper.put(*ch);
+ }
+ }
+
+#if GTEST_HAS_STD_STRING
+ return String(helper.str().c_str());
+#else
+ const String str(helper.str(), helper.pcount());
+ helper.freeze(false);
+ ss->freeze(false);
+ return str;
+#endif // GTEST_HAS_STD_STRING
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg) {
+ // Appends the user message if it's non-empty.
+ const String user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+
+ Message msg;
+ msg << gtest_msg << "\n" << user_msg_string;
+
+ return msg.GetString();
+}
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0),
+ elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+ test_part_results_.PushBack(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const TestProperty& test_property) {
+ if (!ValidateTestProperty(test_property)) {
+ return;
+ }
+ MutexLock lock(&test_properites_mutex_);
+ ListNode<TestProperty>* const node_with_matching_key =
+ test_properties_.FindIf(TestPropertyKeyIs(test_property.key()));
+ if (node_with_matching_key == NULL) {
+ test_properties_.PushBack(test_property);
+ return;
+ }
+ TestProperty& property_with_matching_key = node_with_matching_key->element();
+ property_with_matching_key.SetValue(test_property.value());
+}
+
+// Adds a failure if the key is a reserved attribute of Google Test
+// testcase tags. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
+ String key(test_property.key());
+ if (key == "name" || key == "status" || key == "time" || key == "classname") {
+ ADD_FAILURE()
+ << "Reserved key used in RecordProperty(): "
+ << key
+ << " ('name', 'status', 'time', and 'classname' are reserved by "
+ << GTEST_NAME << ")";
+ return false;
+ }
+ return true;
+}
+
+// Clears the object.
+void TestResult::Clear() {
+ test_part_results_.Clear();
+ test_properties_.Clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true iff the test part passed.
+static bool TestPartPassed(const TestPartResult & result) {
+ return result.passed();
+}
+
+// Gets the number of successful test parts.
+int TestResult::successful_part_count() const {
+ return test_part_results_.CountIf(TestPartPassed);
+}
+
+// Returns true iff the test part failed.
+static bool TestPartFailed(const TestPartResult & result) {
+ return result.failed();
+}
+
+// Gets the number of failed test parts.
+int TestResult::failed_part_count() const {
+ return test_part_results_.CountIf(TestPartFailed);
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult & result) {
+ return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+ return test_part_results_.CountIf(TestPartFatallyFailed) > 0;
+}
+
+// Gets the number of all test parts. This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+ return test_part_results_.size();
+}
+
+} // namespace internal
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+ : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+ delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, const char* value) {
+ UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, int value) {
+ Message value_message;
+ value_message << value;
+ RecordProperty(key, value_message.GetString().c_str());
+}
+
+#ifdef GTEST_OS_WINDOWS
+// We are on Windows.
+
+// Adds an "exception thrown" fatal failure to the current test.
+static void AddExceptionThrownFailure(DWORD exception_code,
+ const char* location) {
+ Message message;
+ message << "Exception thrown with code 0x" << std::setbase(16) <<
+ exception_code << std::setbase(10) << " in " << location << ".";
+
+ UnitTest* const unit_test = UnitTest::GetInstance();
+ unit_test->AddTestPartResult(
+ TPRT_FATAL_FAILURE,
+ static_cast<const char *>(NULL),
+ // We have no info about the source file where the exception
+ // occurred.
+ -1, // We have no info on which line caused the exception.
+ message.GetString(),
+ internal::String(""));
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class. This function checks if the current test has the
+// same fixture class as the first test in the current test case. If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ const TestCase* const test_case = impl->current_test_case();
+
+ // Info about the first test in the current test case.
+ const internal::TestInfoImpl* const first_test_info =
+ test_case->test_info_list().Head()->element()->impl();
+ const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();
+ const char* const first_test_name = first_test_info->name();
+
+ // Info about the current test.
+ const internal::TestInfoImpl* const this_test_info =
+ impl->current_test_info()->impl();
+ const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();
+ const char* const this_test_name = this_test_info->name();
+
+ if (this_fixture_id != first_fixture_id) {
+ // Is the first test defined using TEST?
+ const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+ // Is this test defined using TEST?
+ const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+ if (first_is_TEST || this_is_TEST) {
+ // The user mixed TEST and TEST_F in this test case - we'll tell
+ // him/her how to fix it.
+
+ // Gets the name of the TEST and the name of the TEST_F. Note
+ // that first_is_TEST and this_is_TEST cannot both be true, as
+ // the fixture IDs are different for the two tests.
+ const char* const TEST_name =
+ first_is_TEST ? first_test_name : this_test_name;
+ const char* const TEST_F_name =
+ first_is_TEST ? this_test_name : first_test_name;
+
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test case is\n"
+ << "illegal. In test case " << this_test_info->test_case_name()
+ << ",\n"
+ << "test " << TEST_F_name << " is defined using TEST_F but\n"
+ << "test " << TEST_name << " is defined using TEST. You probably\n"
+ << "want to change the TEST to TEST_F or move it to another test\n"
+ << "case.";
+ } else {
+ // The user defined two fixture classes with the same name in
+ // two namespaces - we'll tell him/her how to fix it.
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case "
+ << this_test_info->test_case_name() << ",\n"
+ << "you defined test " << first_test_name
+ << " and test " << this_test_name << "\n"
+ << "using two different test fixture classes. This can happen if\n"
+ << "the two classes are from different namespaces or translation\n"
+ << "units and have the same name. You should probably rename one\n"
+ << "of the classes to put the tests into different test cases.";
+ }
+ return false;
+ }
+
+ return true;
+}
+
+// Runs the test and updates the test result.
+void Test::Run() {
+ if (!HasSameFixtureClass()) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+#if defined(GTEST_OS_WINDOWS) && !defined(__MINGW32__)
+ // We are on Windows.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ SetUp();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");
+ }
+
+ // We will run the test only if SetUp() had no fatal failure.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ TestBody();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "the test body");
+ }
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ TearDown();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");
+ }
+
+#else // We are on Linux, Mac or MingW - exceptions are disabled.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ SetUp();
+
+ // We will run the test only if SetUp() was successful.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ TestBody();
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ TearDown();
+#endif // GTEST_OS_WINDOWS
+}
+
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object via impl_.
+TestInfo::TestInfo(const char* test_case_name,
+ const char* name,
+ const char* test_case_comment,
+ const char* comment,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory) {
+ impl_ = new internal::TestInfoImpl(this, test_case_name, name,
+ test_case_comment, comment,
+ fixture_class_id, factory);
+}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() {
+ delete impl_;
+}
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// test_case_comment: a comment on the test case that will be included in
+// the test output
+// comment: a comment on the test that will be included in the
+// test output
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory) {
+ TestInfo* const test_info =
+ new TestInfo(test_case_name, name, test_case_comment, comment,
+ fixture_class_id, factory);
+ GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+#ifdef GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line) {
+ Message errors;
+ errors
+ << "Attempted redefinition of test case " << test_case_name << ".\n"
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case " << test_case_name << ", you tried\n"
+ << "to define a test using a fixture class different from the one\n"
+ << "used earlier. This can happen if the two fixture classes are\n"
+ << "from different namespaces and have the same name. You should\n"
+ << "probably rename one of the classes to put the tests into different\n"
+ << "test cases.";
+
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors.GetString().c_str());
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+} // namespace internal
+
+// Returns the test case name.
+const char* TestInfo::test_case_name() const {
+ return impl_->test_case_name();
+}
+
+// Returns the test name.
+const char* TestInfo::name() const {
+ return impl_->name();
+}
+
+// Returns the test case comment.
+const char* TestInfo::test_case_comment() const {
+ return impl_->test_case_comment();
+}
+
+// Returns the test comment.
+const char* TestInfo::comment() const {
+ return impl_->comment();
+}
+
+// Returns true if this test should run.
+bool TestInfo::should_run() const { return impl_->should_run(); }
+
+// Returns the result of the test.
+const internal::TestResult* TestInfo::result() const { return impl_->result(); }
+
+// Increments the number of death tests encountered in this test so
+// far.
+int TestInfo::increment_death_test_count() {
+ return impl_->result()->increment_death_test_count();
+}
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+ // Constructor.
+ //
+ // TestNameIs has NO default constructor.
+ explicit TestNameIs(const char* name)
+ : name_(name) {}
+
+ // Returns true iff the test name of test_info matches name_.
+ bool operator()(const TestInfo * test_info) const {
+ return test_info && internal::String(test_info->name()).Compare(name_) == 0;
+ }
+
+ private:
+ internal::String name_;
+};
+
+} // namespace
+
+// Finds and returns a TestInfo with the given name. If one doesn't
+// exist, returns NULL.
+TestInfo * TestCase::GetTestInfo(const char* test_name) {
+ // Can we find a TestInfo with the given name?
+ internal::ListNode<TestInfo *> * const node = test_info_list_->FindIf(
+ TestNameIs(test_name));
+
+ // Returns the TestInfo found.
+ return node ? node->element() : NULL;
+}
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+#ifdef GTEST_HAS_PARAM_TEST
+ if (!parameterized_tests_registered_) {
+ parameterized_test_registry_.RegisterTests();
+ parameterized_tests_registered_ = true;
+ }
+#endif
+}
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfoImpl::Run() {
+ if (!should_run_) return;
+
+ // Tells UnitTest where to store test result.
+ UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(parent_);
+
+ // Notifies the unit test event listener that a test is about to
+ // start.
+ UnitTestEventListenerInterface* const result_printer =
+ impl->result_printer();
+ result_printer->OnTestStart(parent_);
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+#if defined(GTEST_OS_WINDOWS) && !defined(__MINGW32__)
+ // We are on Windows.
+ Test* test = NULL;
+
+ __try {
+ // Creates the test object.
+ test = factory_->CreateTest();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(),
+ "the test fixture's constructor");
+ return;
+ }
+#else // We are on Linux, Mac OS or MingW - exceptions are disabled.
+
+ // TODO(wan): If test->Run() throws, test won't be deleted. This is
+ // not a problem now as we don't use exceptions. If we were to
+ // enable exceptions, we should revise the following to be
+ // exception-safe.
+
+ // Creates the test object.
+ Test* test = factory_->CreateTest();
+#endif // GTEST_OS_WINDOWS
+
+ // Runs the test only if the constructor of the test fixture didn't
+ // generate a fatal failure.
+ if (!Test::HasFatalFailure()) {
+ test->Run();
+ }
+
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ delete test;
+ test = NULL;
+
+ result_.set_elapsed_time(GetTimeInMillis() - start);
+
+ // Notifies the unit test event listener that a test has just finished.
+ result_printer->OnTestEnd(parent_);
+
+ // Tells UnitTest to stop associating assertion results to this
+ // test.
+ impl->set_current_test_info(NULL);
+}
+
+} // namespace internal
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+ return test_info_list_->CountIf(TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+ return test_info_list_->CountIf(TestFailed);
+}
+
+int TestCase::disabled_test_count() const {
+ return test_info_list_->CountIf(TestDisabled);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+ return test_info_list_->CountIf(ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+ return test_info_list_->size();
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+// name: name of the test case
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* name, const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc)
+ : name_(name),
+ comment_(comment),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ elapsed_time_(0) {
+ test_info_list_ = new internal::List<TestInfo *>;
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+ // Deletes every Test in the collection.
+ test_info_list_->ForEach(internal::Delete<TestInfo>);
+
+ // Then deletes the Test collection.
+ delete test_info_list_;
+ test_info_list_ = NULL;
+}
+
+// Adds a test to this test case. Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+ test_info_list_->PushBack(test_info);
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_case(this);
+
+ UnitTestEventListenerInterface * const result_printer =
+ impl->result_printer();
+
+ result_printer->OnTestCaseStart(this);
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ set_up_tc_();
+
+ const internal::TimeInMillis start = internal::GetTimeInMillis();
+ test_info_list_->ForEach(internal::TestInfoImpl::RunTest);
+ elapsed_time_ = internal::GetTimeInMillis() - start;
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ tear_down_tc_();
+ result_printer->OnTestCaseEnd(this);
+ impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+ test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult);
+}
+
+
+// class UnitTestEventListenerInterface
+
+// The virtual d'tor.
+UnitTestEventListenerInterface::~UnitTestEventListenerInterface() {
+}
+
+// A result printer that never prints anything. Used in the child process
+// of an exec-style death test to avoid needless output clutter.
+class NullUnitTestResultPrinter : public UnitTestEventListenerInterface {};
+
+// Formats a countable noun. Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static internal::String FormatCountableNoun(int count,
+ const char * singular_form,
+ const char * plural_form) {
+ return internal::String::Format("%d %s", count,
+ count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static internal::String FormatTestCount(int test_count) {
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static internal::String FormatTestCaseCount(int test_case_count) {
+ return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResultType enum to human-friendly string
+// representation. Both TPRT_NONFATAL_FAILURE and TPRT_FATAL_FAILURE
+// are translated to "Failure", as the user usually doesn't care about
+// the difference between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResultType type) {
+ switch (type) {
+ case TPRT_SUCCESS:
+ return "Success";
+
+ case TPRT_NONFATAL_FAILURE:
+ case TPRT_FATAL_FAILURE:
+#ifdef _MSC_VER
+ return "error: ";
+#else
+ return "Failure\n";
+#endif
+ }
+
+ return "Unknown result type";
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(
+ const TestPartResult & test_part_result) {
+ printf("%s %s%s\n",
+ internal::FormatFileLocation(test_part_result.file_name(),
+ test_part_result.line_number()).c_str(),
+ TestPartResultTypeToString(test_part_result.type()),
+ test_part_result.message());
+ fflush(stdout);
+}
+
+// class PrettyUnitTestResultPrinter
+
+namespace internal {
+
+enum GTestColor {
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW
+};
+
+#if defined(GTEST_OS_WINDOWS) && !defined(_WIN32_WCE)
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return FOREGROUND_RED;
+ case COLOR_GREEN: return FOREGROUND_GREEN;
+ case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+ }
+ return 0;
+}
+
+#else
+
+// Returns the ANSI color code for the given color.
+const char* GetAnsiColorCode(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return "1";
+ case COLOR_GREEN: return "2";
+ case COLOR_YELLOW: return "3";
+ };
+ return NULL;
+}
+
+#endif // GTEST_OS_WINDOWS && !_WIN32_WCE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+ const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#ifdef GTEST_OS_WINDOWS
+ // On Windows the TERM variable is usually not set, but the
+ // console there does support colors.
+ return stdout_is_tty;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = GetEnv("TERM");
+ const bool term_supports_color =
+ String::CStringEquals(term, "xterm") ||
+ String::CStringEquals(term, "xterm-color") ||
+ String::CStringEquals(term, "cygwin");
+ return stdout_is_tty && term_supports_color;
+#endif // GTEST_OS_WINDOWS
+ }
+
+ return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+ String::CStringEquals(gtest_color, "1");
+ // We take "yes", "true", "t", and "1" as meaning "yes". If the
+ // value is neither one of these nor "auto", we treat it as "no" to
+ // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+#if defined(_WIN32_WCE) || defined(GTEST_OS_SYMBIAN) || defined(GTEST_OS_ZOS)
+ static const bool use_color = false;
+#else
+ static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0);
+#endif // !_WIN32_WCE
+ // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#if defined(GTEST_OS_WINDOWS) && !defined(_WIN32_WCE)
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+
+ SetConsoleTextAttribute(stdout_handle,
+ GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ vprintf(fmt, args);
+
+ // Restores the text color.
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+ printf("\033[0;3%sm", GetAnsiColorCode(color));
+ vprintf(fmt, args);
+ printf("\033[m"); // Resets the terminal to default.
+#endif // GTEST_OS_WINDOWS && !_WIN32_WCE
+ va_end(args);
+}
+
+} // namespace internal
+
+using internal::ColoredPrintf;
+using internal::COLOR_RED;
+using internal::COLOR_GREEN;
+using internal::COLOR_YELLOW;
+
+// This class implements the UnitTestEventListenerInterface interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface {
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char * test_case, const char * test) {
+ printf("%s.%s", test_case, test);
+ }
+
+ // The following methods override what's in the
+ // UnitTestEventListenerInterface class.
+ virtual void OnUnitTestStart(const UnitTest * unit_test);
+ virtual void OnGlobalSetUpStart(const UnitTest*);
+ virtual void OnTestCaseStart(const TestCase * test_case);
+ virtual void OnTestCaseEnd(const TestCase * test_case);
+ virtual void OnTestStart(const TestInfo * test_info);
+ virtual void OnNewTestPartResult(const TestPartResult * result);
+ virtual void OnTestEnd(const TestInfo * test_info);
+ virtual void OnGlobalTearDownStart(const UnitTest*);
+ virtual void OnUnitTestEnd(const UnitTest * unit_test);
+
+ private:
+ internal::String test_case_name_;
+};
+
+// Called before the unit test starts.
+void PrettyUnitTestResultPrinter::OnUnitTestStart(
+ const UnitTest * unit_test) {
+ const char * const filter = GTEST_FLAG(filter).c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!internal::String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: %s filter = %s\n", GTEST_NAME, filter);
+ }
+
+ const internal::UnitTestImpl* const impl = unit_test->impl();
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(impl->test_to_run_count()).c_str(),
+ FormatTestCaseCount(impl->test_case_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnGlobalSetUpStart(const UnitTest*) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(
+ const TestCase * test_case) {
+ test_case_name_ = test_case->name();
+ const internal::String counts =
+ FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_case_name_.c_str());
+ if (test_case->comment()[0] == '\0') {
+ printf("\n");
+ } else {
+ printf(", where %s\n", test_case->comment());
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(
+ const TestCase * test_case) {
+ if (!GTEST_FLAG(print_time)) return;
+
+ test_case_name_ = test_case->name();
+ const internal::String counts =
+ FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n",
+ counts.c_str(), test_case_name_.c_str(),
+ internal::StreamableToString(test_case->elapsed_time()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) {
+ ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
+ PrintTestName(test_case_name_.c_str(), test_info->name());
+ if (test_info->comment()[0] == '\0') {
+ printf("\n");
+ } else {
+ printf(", where %s\n", test_info->comment());
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) {
+ if (test_info->result()->Passed()) {
+ ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else {
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ }
+ PrintTestName(test_case_name_.c_str(), test_info->name());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms)\n", internal::StreamableToString(
+ test_info->result()->elapsed_time()).c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnNewTestPartResult(
+ const TestPartResult * result) {
+ // If the test part succeeded, we don't need to do anything.
+ if (result->type() == TPRT_SUCCESS)
+ return;
+
+ // Print failure message from the assertion (e.g. expected this and got that).
+ PrintTestPartResult(*result);
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnGlobalTearDownStart(const UnitTest*) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment tear-down\n");
+ fflush(stdout);
+}
+
+namespace internal {
+
+// Internal helper for printing the list of failed tests.
+static void PrintFailedTestsPretty(const UnitTestImpl* impl) {
+ const int failed_test_count = impl->failed_test_count();
+ if (failed_test_count == 0) {
+ return;
+ }
+
+ for (const internal::ListNode<TestCase*>* node = impl->test_cases()->Head();
+ node != NULL; node = node->next()) {
+ const TestCase* const tc = node->element();
+ if (!tc->should_run() || (tc->failed_test_count() == 0)) {
+ continue;
+ }
+ for (const internal::ListNode<TestInfo*>* tinode =
+ tc->test_info_list().Head();
+ tinode != NULL; tinode = tinode->next()) {
+ const TestInfo* const ti = tinode->element();
+ if (!tc->ShouldRunTest(ti) || tc->TestPassed(ti)) {
+ continue;
+ }
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s.%s", ti->test_case_name(), ti->name());
+ if (ti->test_case_comment()[0] != '\0' ||
+ ti->comment()[0] != '\0') {
+ printf(", where %s", ti->test_case_comment());
+ if (ti->test_case_comment()[0] != '\0' &&
+ ti->comment()[0] != '\0') {
+ printf(" and ");
+ }
+ }
+ printf("%s\n", ti->comment());
+ }
+ }
+}
+
+} // namespace internal
+
+void PrettyUnitTestResultPrinter::OnUnitTestEnd(
+ const UnitTest * unit_test) {
+ const internal::UnitTestImpl* const impl = unit_test->impl();
+
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(impl->test_to_run_count()).c_str(),
+ FormatTestCaseCount(impl->test_case_to_run_count()).c_str());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(impl->elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str());
+
+ int num_failures = impl->failed_test_count();
+ if (!impl->Passed()) {
+ const int failed_test_count = impl->failed_test_count();
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+ internal::PrintFailedTestsPretty(impl);
+ printf("\n%2d FAILED %s\n", num_failures,
+ num_failures == 1 ? "TEST" : "TESTS");
+ }
+
+ int num_disabled = impl->disabled_test_count();
+ if (num_disabled) {
+ if (!num_failures) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(COLOR_YELLOW,
+ " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled,
+ num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class UnitTestEventsRepeater
+//
+// This class forwards events to other event listeners.
+class UnitTestEventsRepeater : public UnitTestEventListenerInterface {
+ public:
+ typedef internal::List<UnitTestEventListenerInterface *> Listeners;
+ typedef internal::ListNode<UnitTestEventListenerInterface *> ListenersNode;
+ UnitTestEventsRepeater() {}
+ virtual ~UnitTestEventsRepeater();
+ void AddListener(UnitTestEventListenerInterface *listener);
+
+ virtual void OnUnitTestStart(const UnitTest* unit_test);
+ virtual void OnUnitTestEnd(const UnitTest* unit_test);
+ virtual void OnGlobalSetUpStart(const UnitTest* unit_test);
+ virtual void OnGlobalSetUpEnd(const UnitTest* unit_test);
+ virtual void OnGlobalTearDownStart(const UnitTest* unit_test);
+ virtual void OnGlobalTearDownEnd(const UnitTest* unit_test);
+ virtual void OnTestCaseStart(const TestCase* test_case);
+ virtual void OnTestCaseEnd(const TestCase* test_case);
+ virtual void OnTestStart(const TestInfo* test_info);
+ virtual void OnTestEnd(const TestInfo* test_info);
+ virtual void OnNewTestPartResult(const TestPartResult* result);
+
+ private:
+ Listeners listeners_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater);
+};
+
+UnitTestEventsRepeater::~UnitTestEventsRepeater() {
+ for (ListenersNode* listener = listeners_.Head();
+ listener != NULL;
+ listener = listener->next()) {
+ delete listener->element();
+ }
+}
+
+void UnitTestEventsRepeater::AddListener(
+ UnitTestEventListenerInterface *listener) {
+ listeners_.PushBack(listener);
+}
+
+// Since the methods are identical, use a macro to reduce boilerplate.
+// This defines a member that repeats the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void UnitTestEventsRepeater::Name(const Type* parameter) { \
+ for (ListenersNode* listener = listeners_.Head(); \
+ listener != NULL; \
+ listener = listener->next()) { \
+ listener->element()->Name(parameter); \
+ } \
+}
+
+GTEST_REPEATER_METHOD_(OnUnitTestStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnUnitTestEnd, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalSetUpEnd, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalTearDownStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalTearDownEnd, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult)
+
+#undef GTEST_REPEATER_METHOD_
+
+// End PrettyUnitTestResultPrinter
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface {
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ virtual void OnUnitTestEnd(const UnitTest* unit_test);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(char c) {
+ return c == 0x9 || c == 0xA || c == 0xD;
+ }
+
+ // May c appear in a well-formed XML document?
+ static bool IsValidXmlCharacter(char c) {
+ return IsNormalizableWhitespace(c) || c >= 0x20;
+ }
+
+ // Returns an XML-escaped copy of the input string str. If
+ // is_attribute is true, the text is meant to appear as an attribute
+ // value, and normalizable whitespace is preserved by replacing it
+ // with character references.
+ static internal::String EscapeXml(const char* str,
+ bool is_attribute);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static internal::String EscapeXmlAttribute(const char* str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static internal::String EscapeXmlText(const char* str) {
+ return EscapeXml(str, false);
+ }
+
+ // Prints an XML representation of a TestInfo object.
+ static void PrintXmlTestInfo(FILE* out,
+ const char* test_case_name,
+ const TestInfo* test_info);
+
+ // Prints an XML representation of a TestCase object
+ static void PrintXmlTestCase(FILE* out, const TestCase* test_case);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(FILE* out, const UnitTest* unit_test);
+
+ // Produces a string representing the test properties in a result as space
+ // delimited XML attributes based on the property key="value" pairs.
+ // When the String is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static internal::String TestPropertiesAsXmlAttributes(
+ const internal::TestResult* result);
+
+ // The output file.
+ const internal::String output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.c_str() == NULL || output_file_.empty()) {
+ fprintf(stderr, "XML output file may not be null\n");
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) {
+ FILE* xmlout = NULL;
+ internal::FilePath output_file(output_file_);
+ internal::FilePath output_dir(output_file.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ // MSVC 8 deprecates fopen(), so we want to suppress warning 4996
+ // (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS
+ // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ xmlout = fopen(output_file_.c_str(), "w");
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ xmlout = fopen(output_file_.c_str(), "w");
+#endif // GTEST_OS_WINDOWS
+ }
+ if (xmlout == NULL) {
+ // TODO(wan): report the reason of the failure.
+ //
+ // We don't do it for now as:
+ //
+ // 1. There is no urgent need for it.
+ // 2. It's a bit involved to make the errno variable thread-safe on
+ // all three operating systems (Linux, Windows, and Mac OS).
+ // 3. To interpret the meaning of errno in a thread-safe way,
+ // we need the strerror_r() function, which is not available on
+ // Windows.
+ fprintf(stderr,
+ "Unable to open file \"%s\"\n",
+ output_file_.c_str());
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ PrintXmlUnitTest(xmlout, unit_test);
+ fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str. If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str,
+ bool is_attribute) {
+ Message m;
+
+ if (str != NULL) {
+ for (const char* src = str; *src; ++src) {
+ switch (*src) {
+ case '<':
+ m << "&lt;";
+ break;
+ case '>':
+ m << "&gt;";
+ break;
+ case '&':
+ m << "&amp;";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "&apos;";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << "&quot;";
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(*src)) {
+ if (is_attribute && IsNormalizableWhitespace(*src))
+ m << internal::String::Format("&#x%02X;", unsigned(*src));
+ else
+ m << *src;
+ }
+ break;
+ }
+ }
+ }
+
+ return m.GetString();
+}
+
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuite name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
+// </testcase>
+// </testsuite>
+// </testsuite>
+
+namespace internal {
+
+// Formats the given time in milliseconds as seconds. The returned
+// C-string is owned by this function and cannot be released by the
+// caller. Calling the function again invalidates the previous
+// result.
+const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+ static String str;
+ str = (Message() << (ms/1000.0)).GetString();
+ return str.c_str();
+}
+
+} // namespace internal
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
+ const char* test_case_name,
+ const TestInfo* test_info) {
+ const internal::TestResult * const result = test_info->result();
+ const internal::List<TestPartResult> &results = result->test_part_results();
+ fprintf(out,
+ " <testcase name=\"%s\" status=\"%s\" time=\"%s\" "
+ "classname=\"%s\"%s",
+ EscapeXmlAttribute(test_info->name()).c_str(),
+ test_info->should_run() ? "run" : "notrun",
+ internal::FormatTimeInMillisAsSeconds(result->elapsed_time()),
+ EscapeXmlAttribute(test_case_name).c_str(),
+ TestPropertiesAsXmlAttributes(result).c_str());
+
+ int failures = 0;
+ for (const internal::ListNode<TestPartResult>* part_node = results.Head();
+ part_node != NULL;
+ part_node = part_node->next()) {
+ const TestPartResult& part = part_node->element();
+ if (part.failed()) {
+ const internal::String message =
+ internal::String::Format("%s:%d\n%s", part.file_name(),
+ part.line_number(), part.message());
+ if (++failures == 1)
+ fprintf(out, ">\n");
+ fprintf(out,
+ " <failure message=\"%s\" type=\"\"><![CDATA[%s]]>"
+ "</failure>\n",
+ EscapeXmlAttribute(part.summary()).c_str(), message.c_str());
+ }
+ }
+
+ if (failures == 0)
+ fprintf(out, " />\n");
+ else
+ fprintf(out, " </testcase>\n");
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
+ const TestCase* test_case) {
+ fprintf(out,
+ " <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
+ "disabled=\"%d\" ",
+ EscapeXmlAttribute(test_case->name()).c_str(),
+ test_case->total_test_count(),
+ test_case->failed_test_count(),
+ test_case->disabled_test_count());
+ fprintf(out,
+ "errors=\"0\" time=\"%s\">\n",
+ internal::FormatTimeInMillisAsSeconds(test_case->elapsed_time()));
+ for (const internal::ListNode<TestInfo*>* info_node =
+ test_case->test_info_list().Head();
+ info_node != NULL;
+ info_node = info_node->next()) {
+ PrintXmlTestInfo(out, test_case->name(), info_node->element());
+ }
+ fprintf(out, " </testsuite>\n");
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
+ const UnitTest* unit_test) {
+ const internal::UnitTestImpl* const impl = unit_test->impl();
+ fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(out,
+ "<testsuite tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
+ "errors=\"0\" time=\"%s\" ",
+ impl->total_test_count(),
+ impl->failed_test_count(),
+ impl->disabled_test_count(),
+ internal::FormatTimeInMillisAsSeconds(impl->elapsed_time()));
+ fprintf(out, "name=\"AllTests\">\n");
+ for (const internal::ListNode<TestCase*>* case_node =
+ impl->test_cases()->Head();
+ case_node != NULL;
+ case_node = case_node->next()) {
+ PrintXmlTestCase(out, case_node->element());
+ }
+ fprintf(out, "</testsuite>\n");
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+ const internal::TestResult* result) {
+ using internal::TestProperty;
+ Message attributes;
+ const internal::List<TestProperty>& properties = result->test_properties();
+ for (const internal::ListNode<TestProperty>* property_node =
+ properties.Head();
+ property_node != NULL;
+ property_node = property_node->next()) {
+ const TestProperty& property = property_node->element();
+ attributes << " " << property.key() << "="
+ << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+namespace internal {
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+// L < UnitTest::mutex_
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
+ TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message = message.GetString();
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+// L < UnitTest::mutex_
+ScopedTrace::~ScopedTrace() {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as a String. Parameters:
+//
+// max_depth - the maximum number of stack frames to be included
+// in the trace.
+// skip_count - the number of top frames to be skipped; doesn't count
+// against max_depth.
+//
+// L < mutex_
+// We use "L < mutex_" to denote that the function may acquire mutex_.
+String OsStackTraceGetter::CurrentStackTrace(int, int) {
+ return String("");
+}
+
+// L < mutex_
+void OsStackTraceGetter::UponLeavingGTest() {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+ "... " GTEST_NAME " internal frames ...";
+
+} // namespace internal
+
+// class UnitTest
+
+// Gets the singleton UnitTest object. The first time this method is
+// called, a UnitTest object is constructed and returned. Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest * UnitTest::GetInstance() {
+ // When compiled with MSVC 7.1 in optimized mode, destroying the
+ // UnitTest object upon exiting the program messes up the exit code,
+ // causing successful tests to appear failed. We have to use a
+ // different implementation in this case to bypass the compiler bug.
+ // This implementation makes the compiler happy, at the cost of
+ // leaking the UnitTest object.
+#if _MSC_VER == 1310 && !defined(_DEBUG) // MSVC 7.1 and optimized build.
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // _MSC_VER==1310 && !defined(_DEBUG)
+}
+
+// Registers and returns a global test environment. When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered. After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+ if (env == NULL) {
+ return NULL;
+ }
+
+ impl_->environments()->PushBack(env);
+ impl_->environments_in_reverse_order()->PushFront(env);
+ return env;
+}
+
+// Adds a TestPartResult to the current TestResult object. All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results. The user code should use the
+// assertion macros instead of calling this directly.
+// L < mutex_
+void UnitTest::AddTestPartResult(TestPartResultType result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace) {
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack()->size() > 0) {
+ msg << "\n" << GTEST_NAME << " trace:";
+
+ for (internal::ListNode<internal::TraceInfo>* node =
+ impl_->gtest_trace_stack()->Head();
+ node != NULL;
+ node = node->next()) {
+ const internal::TraceInfo& trace = node->element();
+ msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message;
+ }
+ }
+
+ if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+ msg << internal::kStackTraceMarker << os_stack_trace;
+ }
+
+ const TestPartResult result =
+ TestPartResult(result_type, file_name, line_number,
+ msg.GetString().c_str());
+ impl_->GetTestPartResultReporterForCurrentThread()->
+ ReportTestPartResult(result);
+
+ // If this is a failure and the user wants the debugger to break on
+ // failures ...
+ if (result_type != TPRT_SUCCESS && GTEST_FLAG(break_on_failure)) {
+ // ... then we generate a seg fault.
+ *static_cast<int*>(NULL) = 1;
+ }
+}
+
+// Creates and adds a property to the current TestResult. If a property matching
+// the supplied value already exists, updates its value instead.
+void UnitTest::RecordPropertyForCurrentTest(const char* key,
+ const char* value) {
+ const internal::TestProperty test_property(key, value);
+ impl_->current_test_result()->RecordProperty(test_property);
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+#if defined(GTEST_OS_WINDOWS) && !defined(__MINGW32__)
+
+#if !defined(_WIN32_WCE)
+ // SetErrorMode doesn't exist on CE.
+ if (GTEST_FLAG(catch_exceptions)) {
+ // The user wants Google Test to catch exceptions thrown by the tests.
+
+ // This lets fatal errors be handled by us, instead of causing pop-ups.
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+ }
+#endif // _WIN32_WCE
+
+ __try {
+ return impl_->RunAllTests();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
+ fflush(stdout);
+ return 1;
+ }
+
+#else
+ // We are on Linux, Mac OS or MingW. There is no exception of any kind.
+
+ return impl_->RunAllTests();
+#endif // GTEST_OS_WINDOWS
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+ return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestCase* UnitTest::current_test_case() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestInfo* UnitTest::current_test_info() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_info();
+}
+
+#ifdef GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+// L < mutex_
+internal::ParameterizedTestCaseRegistry&
+ UnitTest::parameterized_test_registry() {
+ return impl_->parameterized_test_registry();
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+ impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+ delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+// L < mutex_
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack()->PushFront(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+// L < mutex_
+void UnitTest::PopGTestTrace() {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack()->PopFront(NULL);
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+#ifdef _MSC_VER
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4355) // Temporarily disables warning 4355
+ // (using this in initializer).
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+#pragma warning(pop) // Restores the warning state again.
+#else
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+#endif // _MSC_VER
+ global_test_part_result_repoter_(
+ &default_global_test_part_result_reporter_),
+ per_thread_test_part_result_reporter_(
+ &default_per_thread_test_part_result_reporter_),
+ test_cases_(),
+#ifdef GTEST_HAS_PARAM_TEST
+ parameterized_test_registry_(),
+ parameterized_tests_registered_(false),
+#endif // GTEST_HAS_PARAM_TEST
+ last_death_test_case_(NULL),
+ current_test_case_(NULL),
+ current_test_info_(NULL),
+ ad_hoc_test_result_(),
+ result_printer_(NULL),
+ os_stack_trace_getter_(NULL),
+#ifdef GTEST_HAS_DEATH_TEST
+ elapsed_time_(0),
+ internal_run_death_test_flag_(NULL),
+ death_test_factory_(new DefaultDeathTestFactory) {
+#else
+ elapsed_time_(0) {
+#endif // GTEST_HAS_DEATH_TEST
+}
+
+UnitTestImpl::~UnitTestImpl() {
+ // Deletes every TestCase.
+ test_cases_.ForEach(internal::Delete<TestCase>);
+
+ // Deletes every Environment.
+ environments_.ForEach(internal::Delete<Environment>);
+
+ // Deletes the current test result printer.
+ delete result_printer_;
+
+ delete os_stack_trace_getter_;
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+ // Constructor.
+ explicit TestCaseNameIs(const String& name)
+ : name_(name) {}
+
+ // Returns true iff the name of test_case matches name_.
+ bool operator()(const TestCase* test_case) const {
+ return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ String name_;
+};
+
+// Finds and returns a TestCase with the given name. If one doesn't
+// exist, creates one and returns it.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+ const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc) {
+ // Can we find a TestCase with the given name?
+ internal::ListNode<TestCase*>* node = test_cases_.FindIf(
+ TestCaseNameIs(test_case_name));
+
+ if (node == NULL) {
+ // No. Let's create one.
+ TestCase* const test_case =
+ new TestCase(test_case_name, comment, set_up_tc, tear_down_tc);
+
+ // Is this a death test case?
+ if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),
+ kDeathTestCaseFilter)) {
+ // Yes. Inserts the test case after the last death test case
+ // defined so far.
+ node = test_cases_.InsertAfter(last_death_test_case_, test_case);
+ last_death_test_case_ = node;
+ } else {
+ // No. Appends to the end of the list.
+ test_cases_.PushBack(test_case);
+ node = test_cases_.Last();
+ }
+ }
+
+ // Returns the TestCase found.
+ return node->element();
+}
+
+// Helpers for setting up / tearing down the given environment. They
+// are for use in the List::ForEach() method.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns 0 if all tests are successful, or 1 otherwise. If any
+// exception is thrown during a test on Windows, this test is
+// considered to be failed, but the rest of the tests will still be
+// run. (We disable exceptions on Linux and Mac OS X, so the issue
+// doesn't apply there.)
+// When parameterized tests are enabled, it explands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+int UnitTestImpl::RunAllTests() {
+ // Makes sure InitGoogleTest() was called.
+ if (!GTestIsInitialized()) {
+ printf("%s",
+ "\nThis test program did NOT call ::testing::InitGoogleTest "
+ "before calling RUN_ALL_TESTS(). Please fix it.\n");
+ return 1;
+ }
+
+ RegisterParameterizedTests();
+
+ // Lists all the tests and exits if the --gtest_list_tests
+ // flag was specified.
+ if (GTEST_FLAG(list_tests)) {
+ ListAllTests();
+ return 0;
+ }
+
+ // True iff we are in a subprocess for running a thread-safe-style
+ // death test.
+ bool in_subprocess_for_death_test = false;
+
+#ifdef GTEST_HAS_DEATH_TEST
+ internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+ in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif // GTEST_HAS_DEATH_TEST
+
+ UnitTestEventListenerInterface * const printer = result_printer();
+
+ // Compares the full test names with the filter to decide which
+ // tests to run.
+ const bool has_tests_to_run = FilterTests() > 0;
+ // True iff at least one test has failed.
+ bool failed = false;
+
+ // How many times to repeat the tests? We don't want to repeat them
+ // when we are inside the subprocess of a death test.
+ const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+ // Repeats forever if the repeat count is negative.
+ const bool forever = repeat < 0;
+ for (int i = 0; forever || i != repeat; i++) {
+ if (repeat != 1) {
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1);
+ }
+
+ // Tells the unit test event listener that the tests are about to
+ // start.
+ printer->OnUnitTestStart(parent_);
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ // Runs each test case if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand.
+ printer->OnGlobalSetUpStart(parent_);
+ environments_.ForEach(SetUpEnvironment);
+ printer->OnGlobalSetUpEnd(parent_);
+
+ // Runs the tests only if there was no fatal failure during global
+ // set-up.
+ if (!Test::HasFatalFailure()) {
+ test_cases_.ForEach(TestCase::RunTestCase);
+ }
+
+ // Tears down all environments in reverse order afterwards.
+ printer->OnGlobalTearDownStart(parent_);
+ environments_in_reverse_order_.ForEach(TearDownEnvironment);
+ printer->OnGlobalTearDownEnd(parent_);
+ }
+
+ elapsed_time_ = GetTimeInMillis() - start;
+
+ // Tells the unit test event listener that the tests have just
+ // finished.
+ printer->OnUnitTestEnd(parent_);
+
+ // Gets the result and clears it.
+ if (!Passed()) {
+ failed = true;
+ }
+ ClearResult();
+ }
+
+ // Returns 0 if all tests passed, or 1 other wise.
+ return failed ? 1 : 0;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests() {
+ int num_runnable_tests = 0;
+ for (const internal::ListNode<TestCase *> *test_case_node =
+ test_cases_.Head();
+ test_case_node != NULL;
+ test_case_node = test_case_node->next()) {
+ TestCase * const test_case = test_case_node->element();
+ const String &test_case_name = test_case->name();
+ test_case->set_should_run(false);
+
+ for (const internal::ListNode<TestInfo *> *test_info_node =
+ test_case->test_info_list().Head();
+ test_info_node != NULL;
+ test_info_node = test_info_node->next()) {
+ TestInfo * const test_info = test_info_node->element();
+ const String test_name(test_info->name());
+ // A test is disabled if test case name or test name matches
+ // kDisableTestFilter.
+ const bool is_disabled =
+ internal::UnitTestOptions::MatchesFilter(test_case_name,
+ kDisableTestFilter) ||
+ internal::UnitTestOptions::MatchesFilter(test_name,
+ kDisableTestFilter);
+ test_info->impl()->set_is_disabled(is_disabled);
+
+ const bool should_run = !is_disabled &&
+ internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+ test_name);
+ test_info->impl()->set_should_run(should_run);
+ test_case->set_should_run(test_case->should_run() || should_run);
+ if (should_run) {
+ num_runnable_tests++;
+ }
+ }
+ }
+ return num_runnable_tests;
+}
+
+// Lists all tests by name.
+void UnitTestImpl::ListAllTests() {
+ for (const internal::ListNode<TestCase*>* test_case_node = test_cases_.Head();
+ test_case_node != NULL;
+ test_case_node = test_case_node->next()) {
+ const TestCase* const test_case = test_case_node->element();
+
+ // Prints the test case name following by an indented list of test nodes.
+ printf("%s.\n", test_case->name());
+
+ for (const internal::ListNode<TestInfo*>* test_info_node =
+ test_case->test_info_list().Head();
+ test_info_node != NULL;
+ test_info_node = test_info_node->next()) {
+ const TestInfo* const test_info = test_info_node->element();
+
+ printf(" %s\n", test_info->name());
+ }
+ }
+ fflush(stdout);
+}
+
+// Sets the unit test result printer.
+//
+// Does nothing if the input and the current printer object are the
+// same; otherwise, deletes the old printer object and makes the
+// input the current printer.
+void UnitTestImpl::set_result_printer(
+ UnitTestEventListenerInterface* result_printer) {
+ if (result_printer_ != result_printer) {
+ delete result_printer_;
+ result_printer_ = result_printer;
+ }
+}
+
+// Returns the current unit test result printer if it is not NULL;
+// otherwise, creates an appropriate result printer, makes it the
+// current printer, and returns it.
+UnitTestEventListenerInterface* UnitTestImpl::result_printer() {
+ if (result_printer_ != NULL) {
+ return result_printer_;
+ }
+
+#ifdef GTEST_HAS_DEATH_TEST
+ if (internal_run_death_test_flag_.get() != NULL) {
+ result_printer_ = new NullUnitTestResultPrinter;
+ return result_printer_;
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater;
+ const String& output_format = internal::UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ repeater->AddListener(new XmlUnitTestResultPrinter(
+ internal::UnitTestOptions::GetOutputFile().c_str()));
+ } else if (output_format != "") {
+ printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+ output_format.c_str());
+ fflush(stdout);
+ }
+ repeater->AddListener(new PrettyUnitTestResultPrinter);
+ result_printer_ = repeater;
+ return result_printer_;
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+ OsStackTraceGetterInterface* getter) {
+ if (os_stack_trace_getter_ != getter) {
+ delete os_stack_trace_getter_;
+ os_stack_trace_getter_ = getter;
+ }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+ if (os_stack_trace_getter_ == NULL) {
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+internal::TestResult* UnitTestImpl::current_test_result() {
+ return current_test_info_ ?
+ current_test_info_->impl()->result() : &ad_hoc_test_result_;
+}
+
+// TestInfoImpl constructor. The new instance assumes ownership of the test
+// factory object.
+TestInfoImpl::TestInfoImpl(TestInfo* parent,
+ const char* test_case_name,
+ const char* name,
+ const char* test_case_comment,
+ const char* comment,
+ TypeId fixture_class_id,
+ internal::TestFactoryBase* factory) :
+ parent_(parent),
+ test_case_name_(String(test_case_name)),
+ name_(String(name)),
+ test_case_comment_(String(test_case_comment)),
+ comment_(String(comment)),
+ fixture_class_id_(fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ factory_(factory) {
+}
+
+// TestInfoImpl destructor.
+TestInfoImpl::~TestInfoImpl() {
+ delete factory_;
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) {
+ // We pass skip_count + 1 to skip this wrapper function in addition
+ // to what the user really wants to skip.
+ return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Returns the number of failed test parts in the given test result object.
+int GetFailedPartCount(const TestResult* result) {
+ return result->failed_part_count();
+}
+
+// Parses a string as a command line flag. The string should have
+// the format "--flag=value". When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+ const char* flag,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == NULL || flag == NULL) return NULL;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX.
+ const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX, flag);
+ const size_t flag_len = flag_str.GetLength();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return NULL;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test. The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+ for (int i = 1; i < *argc; i++) {
+ const String arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseBoolFlag;
+ using internal::ParseInt32Flag;
+ using internal::ParseStringFlag;
+
+ // Do we see a Google Test flag?
+ if (ParseBoolFlag(arg, kBreakOnFailureFlag,
+ &GTEST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ &GTEST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ &GTEST_FLAG(death_test_style)) ||
+ ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ &GTEST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+ ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+ ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat))
+ ) {
+ // Yes. Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ }
+ }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+ g_init_gtest_count++;
+
+ // We don't want to run the initialization code twice.
+ if (g_init_gtest_count != 1) return;
+
+ if (*argc <= 0) return;
+
+ internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#ifdef GTEST_HAS_DEATH_TEST
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ ParseGoogleTestFlagsOnly(argc, argv);
+}
+
+} // namespace internal
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+} // namespace testing
diff --git a/utils/unittest/googletest/include/gtest/gtest-death-test.h b/utils/unittest/googletest/include/gtest/gtest-death-test.h
new file mode 100644
index 000000000000..f0e109a3a3a8
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest-death-test.h
@@ -0,0 +1,209 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests. It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include <gtest/internal/gtest-death-test-internal.h>
+
+namespace testing {
+
+// This flag controls the style of death tests. Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+// 1. It generates a warning if there is more than one active
+// thread. This is because it's safe to fork() or clone() only
+// when there is a single thread.
+//
+// 2. The parent process clone()s a sub-process and runs the death
+// test in it; the sub-process exits with code 0 at the end of the
+// death test, if it hasn't exited already.
+//
+// 3. The parent process waits for the sub-process to terminate.
+//
+// 4. The parent process checks the exit code and error message of
+// the sub-process.
+//
+// Examples:
+//
+// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+// for (int i = 0; i < 5; i++) {
+// EXPECT_DEATH(server.ProcessRequest(i),
+// "Invalid request .* in ProcessRequest()")
+// << "Failed to die on request " << i);
+// }
+//
+// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+// bool KilledBySIGHUP(int exit_code) {
+// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+// }
+//
+// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// Known caveats:
+//
+// A "threadsafe" style death test obtains the path to the test
+// program from argv[0] and re-executes it in the sub-process. For
+// simplicity, the current implementation doesn't search the PATH
+// when launching the sub-process. This means that the user must
+// invoke the test program via a path that contains at least one
+// path separator (e.g. path/to/foo_test and
+// /absolute/path/to/bar_test are fine, but foo_test is not). This
+// is rarely a problem as people usually don't put the test binary
+// directory in PATH.
+//
+// TODO(wan@google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+#define ASSERT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+#define ASSERT_DEATH(statement, regex) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_DEATH(statement, regex) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class ExitedWithCode {
+ public:
+ explicit ExitedWithCode(int exit_code);
+ bool operator()(int exit_status) const;
+ private:
+ const int exit_code_;
+};
+
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class KilledBySignal {
+ public:
+ explicit KilledBySignal(int signum);
+ bool operator()(int exit_status) const;
+ private:
+ const int signum_;
+};
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+// if (sideeffect) {
+// *sideeffect = 12;
+// }
+// LOG(DFATAL) << "death";
+// return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// int sideeffect = 0;
+// // Only asserts in dbg.
+// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+// // opt-mode has sideeffect visible.
+// EXPECT_EQ(12, sideeffect);
+// #else
+// // dbg-mode no visible sideeffect.
+// EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects. A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+// // Side-effects here will have an effect after this statement in
+// // opt mode, but none in debug mode.
+// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+#ifdef NDEBUG
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (false)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (false)
+
+#else
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+
+#endif // NDEBUG for EXPECT_DEBUG_DEATH
+#endif // GTEST_HAS_DEATH_TEST
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest-message.h b/utils/unittest/googletest/include/gtest/gtest-message.h
new file mode 100644
index 000000000000..7effd086478e
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest-message.h
@@ -0,0 +1,224 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+// 1. You stream a bunch of values to a Message object.
+// It will remember the text in a StrStream.
+// 2. Then you stream the Message object to an ostream.
+// This causes the text in the Message to be streamed
+// to the ostream.
+//
+// For example;
+//
+// testing::Message foo;
+// foo << 1 << " != " << 2;
+// std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from. In particular, its
+// destructor is not virtual.
+//
+// Note that StrStream behaves differently in gcc and in MSVC. You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do). The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class Message {
+ private:
+ // The type of basic IO manipulators (endl, ends, and flush) for
+ // narrow streams.
+ typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+ // Constructs an empty Message.
+ // We allocate the StrStream separately because it otherwise each use of
+ // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+ // stack frame leading to huge stack frames in some cases; gcc does not reuse
+ // the stack space.
+ Message() : ss_(new internal::StrStream) {}
+
+ // Copy constructor.
+ Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT
+ *ss_ << msg.GetString();
+ }
+
+ // Constructs a Message from a C-string.
+ explicit Message(const char* str) : ss_(new internal::StrStream) {
+ *ss_ << str;
+ }
+
+ ~Message() { delete ss_; }
+#ifdef GTEST_OS_SYMBIAN
+ // Streams a value (either a pointer or not) to this object.
+ template <typename T>
+ inline Message& operator <<(const T& value) {
+ StreamHelper(typename internal::is_pointer<T>::type(), value);
+ return *this;
+ }
+#else
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator <<(const T& val) {
+ ::GTestStreamToHelper(ss_, val);
+ return *this;
+ }
+
+ // Streams a pointer value to this object.
+ //
+ // This function is an overload of the previous one. When you
+ // stream a pointer to a Message, this definition will be used as it
+ // is more specialized. (The C++ Standard, section
+ // [temp.func.order].) If you stream a non-pointer, then the
+ // previous definition will be used.
+ //
+ // The reason for this overload is that streaming a NULL pointer to
+ // ostream is undefined behavior. Depending on the compiler, you
+ // may get "0", "(nil)", "(null)", or an access violation. To
+ // ensure consistent result across compilers, we always treat NULL
+ // as "(null)".
+ template <typename T>
+ inline Message& operator <<(T* const& pointer) { // NOLINT
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_, pointer);
+ }
+ return *this;
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // Since the basic IO manipulators are overloaded for both narrow
+ // and wide streams, we have to provide this specialized definition
+ // of operator <<, even though its body is the same as the
+ // templatized version above. Without this definition, streaming
+ // endl or other basic IO manipulators to Message will confuse the
+ // compiler.
+ Message& operator <<(BasicNarrowIoManip val) {
+ *ss_ << val;
+ return *this;
+ }
+
+ // Instead of 1/0, we want to see true/false for bool values.
+ Message& operator <<(bool b) {
+ return *this << (b ? "true" : "false");
+ }
+
+ // These two overloads allow streaming a wide C string to a Message
+ // using the UTF-8 encoding.
+ Message& operator <<(const wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+ Message& operator <<(wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+
+#if GTEST_HAS_STD_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::std::wstring& wstr);
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::wstring& wstr);
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+ // Gets the text streamed to this object so far as a String.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::String GetString() const {
+ return internal::StrStreamToString(ss_);
+ }
+
+ private:
+#ifdef GTEST_OS_SYMBIAN
+ // These are needed as the Nokia Symbian Compiler cannot decide between
+ // const T& and const T* in a function template. The Nokia compiler _can_
+ // decide between class template specializations for T and T*, so a
+ // tr1::type_traits-like is_pointer works, and we can overload on that.
+ template <typename T>
+ inline void StreamHelper(internal::true_type dummy, T* pointer) {
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_, pointer);
+ }
+ }
+ template <typename T>
+ inline void StreamHelper(internal::false_type dummy, const T& value) {
+ ::GTestStreamToHelper(ss_, value);
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // We'll hold the text streamed to this object here.
+ internal::StrStream* const ss_;
+
+ // We declare (but don't implement) this to prevent the compiler
+ // from implementing the assignment operator.
+ void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+ return os << sb.GetString();
+}
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest-param-test.h b/utils/unittest/googletest/include/gtest/gtest-param-test.h
new file mode 100644
index 000000000000..2d63237f562a
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest-param-test.h
@@ -0,0 +1,1385 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It must be derived from testing::TestWithParam<T>, where T is
+// the type of your parameter values. TestWithParam<T> is itself derived
+// from testing::Test. T can be any copyable type. If it's a raw pointer,
+// you are responsible for managing the lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions are evaluated in
+// RUN_ALL_TESTS(), after main() has started. This allows evaluation of
+// parameter list based on command line parameters.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+
+#endif // 0
+
+
+#include <utility>
+
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_HAS_PARAM_TEST
+
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-param-util.h>
+#include <gtest/internal/gtest-param-util-generated.h>
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
+ ForwardIterator begin,
+ ForwardIterator end) {
+ typedef typename ::std::iterator_traits<ForwardIterator>::value_type
+ ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container) {
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1) {
+ return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
+ return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
+ return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
+ return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5) {
+ return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6) {
+ return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7) {
+ return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+ v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
+ return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+ v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
+ return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
+ return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) {
+ return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) {
+ return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) {
+ return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
+ return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
+ return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16) {
+ return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17) {
+ return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18) {
+ return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
+ return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
+ return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
+ return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22) {
+ return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23) {
+ return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24) {
+ return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
+ return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) {
+ return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) {
+ return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) {
+ return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) {
+ return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
+ return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
+ return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32) {
+ return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33) {
+ return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34) {
+ return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
+ return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
+ return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37) {
+ return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38) {
+ return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+ v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38, T39 v39) {
+ return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+ v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+ T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+ T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
+ return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+ v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
+ return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+ v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) {
+ return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+ v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) {
+ return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+ v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) {
+ return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+ v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
+ return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+ v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
+ return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
+ return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+ T48 v48) {
+ return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+ v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+ T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+ T47 v47, T48 v48, T49 v49) {
+ return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+ v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+ T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+ T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
+ return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+ v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+ return Values(false, true);
+}
+
+#ifdef GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<tuple(bool, bool)> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+ const Generator1& g1, const Generator2& g2) {
+ return internal::CartesianProductHolder2<Generator1, Generator2>(
+ g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3) {
+ return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+ g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4) {
+ return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4>(
+ g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5) {
+ return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5>(
+ g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6) {
+ return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6>(
+ g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7) {
+ return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7>(
+ g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8) {
+ return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8>(
+ g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8,
+ Generator9> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9) {
+ return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8, typename Generator9,
+ typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9,
+ const Generator10& g10) {
+ return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+#endif // GTEST_HAS_COMBINE
+
+
+
+#define TEST_P(test_case_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ : public test_case_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+ virtual void TestBody(); \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_case_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+ int gtest_##prefix##test_case_name##_dummy_ = \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+ #prefix, \
+ &gtest_##prefix##test_case_name##_EvalGenerator_, \
+ __FILE__, __LINE__)
+
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest-spi.h b/utils/unittest/googletest/include/gtest/gtest-spi.h
new file mode 100644
index 000000000000..a4e387a31266
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest-spi.h
@@ -0,0 +1,221 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <gtest/gtest.h>
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class ScopedFakeTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ // The two possible mocking modes of this object.
+ enum InterceptMode {
+ INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
+ INTERCEPT_ALL_THREADS // Intercepts all failures.
+ };
+
+ // The c'tor sets this object as the test part result reporter used
+ // by Google Test. The 'result' parameter specifies where to report the
+ // results. This reporter will only catch failures generated in the current
+ // thread. DEPRECATED
+ explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+ // Same as above, but you can choose the interception scope of this object.
+ ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+ TestPartResultArray* result);
+
+ // The d'tor restores the previous test part result reporter.
+ virtual ~ScopedFakeTestPartResultReporter();
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+ void Init();
+
+ const InterceptMode intercept_mode_;
+ TestPartResultReporterInterface* old_reporter_;
+ TestPartResultArray* const result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+class SingleFailureChecker {
+ public:
+ // The constructor remembers the arguments.
+ SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResultType type,
+ const char* substr);
+ ~SingleFailureChecker();
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResultType type_;
+ const String substr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures. It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - 'statement' cannot reference local non-static variables or
+// non-static members of the current object.
+// - 'statement' cannot return a value.
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (false)
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ALL_THREADS, &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (false)
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures. It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+ statement;\
+ }\
+ } while (false)
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
+ &gtest_failures);\
+ statement;\
+ }\
+ } while (false)
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest-test-part.h b/utils/unittest/googletest/include/gtest/gtest-test-part.h
new file mode 100644
index 000000000000..1a281afb32ab
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest-test-part.h
@@ -0,0 +1,179 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+
+// The possible outcomes of a test part (i.e. an assertion or an
+// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+enum TestPartResultType {
+ TPRT_SUCCESS, // Succeeded.
+ TPRT_NONFATAL_FAILURE, // Failed but the test can continue.
+ TPRT_FATAL_FAILURE // Failed and the test should be terminated.
+};
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class TestPartResult {
+ public:
+ // C'tor. TestPartResult does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestPartResult object.
+ TestPartResult(TestPartResultType type,
+ const char* file_name,
+ int line_number,
+ const char* message)
+ : type_(type),
+ file_name_(file_name),
+ line_number_(line_number),
+ summary_(ExtractSummary(message)),
+ message_(message) {
+ }
+
+ // Gets the outcome of the test part.
+ TestPartResultType type() const { return type_; }
+
+ // Gets the name of the source file where the test part took place, or
+ // NULL if it's unknown.
+ const char* file_name() const { return file_name_.c_str(); }
+
+ // Gets the line in the source file where the test part took place,
+ // or -1 if it's unknown.
+ int line_number() const { return line_number_; }
+
+ // Gets the summary of the failure message.
+ const char* summary() const { return summary_.c_str(); }
+
+ // Gets the message associated with the test part.
+ const char* message() const { return message_.c_str(); }
+
+ // Returns true iff the test part passed.
+ bool passed() const { return type_ == TPRT_SUCCESS; }
+
+ // Returns true iff the test part failed.
+ bool failed() const { return type_ != TPRT_SUCCESS; }
+
+ // Returns true iff the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == TPRT_NONFATAL_FAILURE; }
+
+ // Returns true iff the test part fatally failed.
+ bool fatally_failed() const { return type_ == TPRT_FATAL_FAILURE; }
+ private:
+ TestPartResultType type_;
+
+ // Gets the summary of the failure message by omitting the stack
+ // trace in it.
+ static internal::String ExtractSummary(const char* message);
+
+ // The name of the source file where the test part took place, or
+ // NULL if the source file is unknown.
+ internal::String file_name_;
+ // The line in the source file where the test part took place, or -1
+ // if the line number is unknown.
+ int line_number_;
+ internal::String summary_; // The test failure summary.
+ internal::String message_; // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// We define this class as we cannot use STL containers when compiling
+// Google Test with MSVC 7.1 and exceptions disabled.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class TestPartResultArray {
+ public:
+ TestPartResultArray();
+ ~TestPartResultArray();
+
+ // Appends the given TestPartResult to the array.
+ void Append(const TestPartResult& result);
+
+ // Returns the TestPartResult at the given index (0-based).
+ const TestPartResult& GetTestPartResult(int index) const;
+
+ // Returns the number of TestPartResult objects in the array.
+ int size() const;
+ private:
+ // Internally we use a list to simulate the array. Yes, this means
+ // that random access is O(N) in time, but it's OK for its purpose.
+ internal::List<TestPartResult>* const list_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+ virtual ~TestPartResultReporterInterface() {}
+
+ virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class HasNewFatalFailureHelper : public TestPartResultReporterInterface {
+ public:
+ HasNewFatalFailureHelper();
+ virtual ~HasNewFatalFailureHelper();
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+ bool has_new_fatal_failure_;
+ TestPartResultReporterInterface* original_reporter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest-typed-test.h b/utils/unittest/googletest/include/gtest/gtest-typed-test.h
new file mode 100644
index 000000000000..dec42cf47012
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest-typed-test.h
@@ -0,0 +1,253 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list. You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+ ...
+ typedef std::list<T> List;
+ static T shared_;
+ T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list. The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ // Since we are inside a derived class template, C++ requires use to
+ // visit the members of FooTest via 'this'.
+ TypeParam n = this->value_;
+
+ // To visit static members of the fixture, add the TestFixture::
+ // prefix.
+ n += TestFixture::shared_;
+
+ // To refer to typedefs in the fixture, add the "typename
+ // TestFixture::" prefix.
+ typename TestFixture::List values;
+ values.push_back(n);
+ ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type. Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are. The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have. Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly. Here's an example:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ TypeParam n = 0;
+ ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them. The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+ DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want. If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name. Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif // 0
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-type-util.h>
+
+// Implements typed tests.
+
+#ifdef GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+#define TYPED_TEST_CASE(CaseName, Types) \
+ typedef ::testing::internal::TypeList<Types>::type \
+ GTEST_TYPE_PARAMS_(CaseName)
+
+#define TYPED_TEST(CaseName, TestName) \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ bool gtest_##CaseName##_##TestName##_registered_ = \
+ ::testing::internal::TypeParameterizedTest< \
+ CaseName, \
+ ::testing::internal::TemplateSel< \
+ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+ GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+ "", #CaseName, #TestName, 0); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#ifdef GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in. The exact
+// name of the namespace is subject to change without notice.
+#define GTEST_CASE_NAMESPACE_(TestCaseName) \
+ gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+ gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+ gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+#define TYPED_TEST_CASE_P(CaseName) \
+ static ::testing::internal::TypedTestCasePState \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+#define TYPED_TEST_P(CaseName, TestName) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ static bool gtest_##TestName##_defined_ = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+ __FILE__, __LINE__, #CaseName, #TestName); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+ __FILE__, __LINE__, #__VA_ARGS__)
+
+#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+ bool gtest_##Prefix##_##CaseName = \
+ ::testing::internal::TypeParameterizedTestCase<CaseName, \
+ GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+ ::testing::internal::TypeList<Types>::type>::Register(\
+ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h
new file mode 100644
index 000000000000..ebd3123b043d
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest.h
@@ -0,0 +1,1317 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test. It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+// The following platform macros are used throughout Google Test:
+// _WIN32_WCE Windows CE (set in project files)
+//
+// Note that even though _MSC_VER and _WIN32_WCE really indicate a compiler
+// and a Win32 implementation, respectively, we use them to indicate the
+// combination of compiler - Win 32 API - C library, since the code currently
+// only supports:
+// Windows proper with Visual C++ and MS C library (_MSC_VER && !_WIN32_WCE) and
+// Windows Mobile with Visual C++ and no C library (_WIN32_WCE).
+
+#include <limits>
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+#include <gtest/gtest-death-test.h>
+#include <gtest/gtest-message.h>
+#include <gtest/gtest-param-test.h>
+#include <gtest/gtest_prod.h>
+#include <gtest/gtest-test-part.h>
+#include <gtest/gtest-typed-test.h>
+
+// Depending on the platform, different string classes are available.
+// On Windows, ::std::string compiles only when exceptions are
+// enabled. On Linux, in addition to ::std::string, Google also makes
+// use of class ::string, which has the same interface as
+// ::std::string, but has a different implementation.
+//
+// The user can tell us whether ::std::string is available in his
+// environment by defining the macro GTEST_HAS_STD_STRING to either 1
+// or 0 on the compiler command line. He can also define
+// GTEST_HAS_GLOBAL_STRING to 1 to indicate that ::string is available
+// AND is a distinct type to ::std::string, or define it to 0 to
+// indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_STD_STRING to 1 and
+// GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_STD_STRING and/or
+// GTEST_HAS_GLOBAL_STRING, they are defined heuristically.
+
+namespace testing {
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+namespace internal {
+
+class GTestFlagSaver;
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared in gtest-internal.h but defined here, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable) {
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+
+// A class for indicating whether an assertion was successful. When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that described how it failed.
+//
+// This class is useful for defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// The constructor of AssertionResult is private. To create an
+// instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// For example, in order to be able to write:
+//
+// // Verifies that Foo() returns an even number.
+// EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you just need to define:
+//
+// testing::AssertionResult IsEven(const char* expr, int n) {
+// if ((n % 2) == 0) return testing::AssertionSuccess();
+//
+// Message msg;
+// msg << "Expected: " << expr << " is even\n"
+// << " Actual: it's " << n;
+// return testing::AssertionFailure(msg);
+// }
+//
+// If Foo() returns 5, you will see the following message:
+//
+// Expected: Foo() is even
+// Actual: it's 5
+class AssertionResult {
+ public:
+ // Declares factory functions for making successful and failed
+ // assertion results as friends.
+ friend AssertionResult AssertionSuccess();
+ friend AssertionResult AssertionFailure(const Message&);
+
+ // Returns true iff the assertion succeeded.
+ operator bool() const { return failure_message_.c_str() == NULL; } // NOLINT
+
+ // Returns the assertion's failure message.
+ const char* failure_message() const { return failure_message_.c_str(); }
+
+ private:
+ // The default constructor. It is used when the assertion succeeded.
+ AssertionResult() {}
+
+ // The constructor used when the assertion failed.
+ explicit AssertionResult(const internal::String& failure_message);
+
+ // Stores the assertion's failure message.
+ internal::String failure_message_;
+};
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result with the given failure message.
+AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { ... }
+// virtual void TearDown() { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class Test {
+ public:
+ friend class internal::TestInfoImpl;
+
+ // Defines types for pointers to functions that set up and tear down
+ // a test case.
+ typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+ typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+ // The d'tor is virtual as we intend to inherit from Test.
+ virtual ~Test();
+
+ // Sets up the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::SetUpTestCase() before running the first
+ // test in test case Foo. Hence a sub-class can define its own
+ // SetUpTestCase() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestCase() {}
+
+ // Tears down the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::TearDownTestCase() after running the last
+ // test in test case Foo. Hence a sub-class can define its own
+ // TearDownTestCase() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestCase() {}
+
+ // Returns true iff the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Logs a property for the current test. Only the last value for a given
+ // key is remembered.
+ // These are public static so they can be called from utility functions
+ // that are not members of the test fixture.
+ // The arguments are const char* instead strings, as Google Test is used
+ // on platforms where string doesn't compile.
+ //
+ // Note that a driving consideration for these RecordProperty methods
+ // was to produce xml output suited to the Greenspan charting utility,
+ // which at present will only chart values that fit in a 32-bit int. It
+ // is the user's responsibility to restrict their values to 32-bit ints
+ // if they intend them to be used with Greenspan.
+ static void RecordProperty(const char* key, const char* value);
+ static void RecordProperty(const char* key, int value);
+
+ protected:
+ // Creates a Test object.
+ Test();
+
+ // Sets up the test fixture.
+ virtual void SetUp();
+
+ // Tears down the test fixture.
+ virtual void TearDown();
+
+ private:
+ // Returns true iff the current test has the same fixture class as
+ // the first test in the current test case.
+ static bool HasSameFixtureClass();
+
+ // Runs the test after the test fixture has been set up.
+ //
+ // A sub-class must implement this to define the test logic.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+ // Instead, use the TEST or TEST_F macro.
+ virtual void TestBody() = 0;
+
+ // Sets up, executes, and tears down the test.
+ void Run();
+
+ // Uses a GTestFlagSaver to save and restore all Google Test flags.
+ const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+ // Often a user mis-spells SetUp() as Setup() and spends a long time
+ // wondering why it is never called by Google Test. The declaration of
+ // the following method is solely for catching such an error at
+ // compile time:
+ //
+ // - The return type is deliberately chosen to be not void, so it
+ // will be a conflict if a user declares void Setup() in his test
+ // fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if a user calls it from his test fixture.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION.
+ //
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+ // We disallow copying Tests.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+
+// A TestInfo object stores the following information about a test:
+//
+// Test case name
+// Test name
+// Whether the test should be run
+// A function pointer that creates the test object when invoked
+// Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class TestInfo {
+ public:
+ // Destructs a TestInfo object. This function is not virtual, so
+ // don't inherit from TestInfo.
+ ~TestInfo();
+
+ // Returns the test case name.
+ const char* test_case_name() const;
+
+ // Returns the test name.
+ const char* name() const;
+
+ // Returns the test case comment.
+ const char* test_case_comment() const;
+
+ // Returns the test comment.
+ const char* comment() const;
+
+ // Returns true if this test should run.
+ //
+ // Google Test allows the user to filter the tests by their full names.
+ // The full name of a test Bar in test case Foo is defined as
+ // "Foo.Bar". Only the tests that match the filter will run.
+ //
+ // A filter is a colon-separated list of glob (not regex) patterns,
+ // optionally followed by a '-' and a colon-separated list of
+ // negative patterns (tests to exclude). A test is run if it
+ // matches one of the positive patterns and does not match any of
+ // the negative patterns.
+ //
+ // For example, *A*:Foo.* is a filter that matches any string that
+ // contains the character 'A' or starts with "Foo.".
+ bool should_run() const;
+
+ // Returns the result of the test.
+ const internal::TestResult* result() const;
+ private:
+#ifdef GTEST_HAS_DEATH_TEST
+ friend class internal::DefaultDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+ friend class internal::TestInfoImpl;
+ friend class internal::UnitTestImpl;
+ friend class Test;
+ friend class TestCase;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
+
+ // Increments the number of death tests encountered in this test so
+ // far.
+ int increment_death_test_count();
+
+ // Accessors for the implementation object.
+ internal::TestInfoImpl* impl() { return impl_; }
+ const internal::TestInfoImpl* impl() const { return impl_; }
+
+ // Constructs a TestInfo object. The newly constructed instance assumes
+ // ownership of the factory object.
+ TestInfo(const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+
+ // An opaque implementation object.
+ internal::TestInfoImpl* impl_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+// 1. You cannot safely throw from a destructor. This is a problem
+// as in some cases Google Test is used where exceptions are enabled, and
+// we may want to implement ASSERT_* using exceptions where they are
+// available.
+// 2. You cannot use ASSERT_* directly in a constructor or
+// destructor.
+class Environment {
+ public:
+ // The d'tor is virtual as we need to subclass Environment.
+ virtual ~Environment() {}
+
+ // Override this to define how to set up the environment.
+ virtual void SetUp() {}
+
+ // Override this to define how to tear down the environment.
+ virtual void TearDown() {}
+ private:
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// A UnitTest consists of a list of TestCases.
+//
+// This is a singleton class. The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called. This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class UnitTest {
+ public:
+ // Gets the singleton UnitTest object. The first time this method
+ // is called, a UnitTest object is constructed and returned.
+ // Consecutive calls will return the same object.
+ static UnitTest* GetInstance();
+
+ // Registers and returns a global test environment. When a test
+ // program is run, all global test environments will be set-up in
+ // the order they were registered. After all tests in the program
+ // have finished, all global test environments will be torn-down in
+ // the *reverse* order they were registered.
+ //
+ // The UnitTest object takes ownership of the given environment.
+ //
+ // This method can only be called from the main thread.
+ Environment* AddEnvironment(Environment* env);
+
+ // Adds a TestPartResult to the current TestResult object. All
+ // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+ // eventually call this to report their results. The user code
+ // should use the assertion macros instead of calling this directly.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ void AddTestPartResult(TestPartResultType result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace);
+
+ // Adds a TestProperty to the current TestResult object. If the result already
+ // contains a property with the same key, the value will be updated.
+ void RecordPropertyForCurrentTest(const char* key, const char* value);
+
+ // Runs all tests in this UnitTest object and prints the result.
+ // Returns 0 if successful, or 1 otherwise.
+ //
+ // This method can only be called from the main thread.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ int Run() GTEST_MUST_USE_RESULT_;
+
+ // Returns the working directory when the first TEST() or TEST_F()
+ // was executed. The UnitTest object owns the string.
+ const char* original_working_dir() const;
+
+ // Returns the TestCase object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestCase* current_test_case() const;
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const;
+
+#ifdef GTEST_HAS_PARAM_TEST
+ // Returns the ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry();
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+ private:
+ // ScopedTrace is a friend as it needs to modify the per-thread
+ // trace stack, which is a private member of UnitTest.
+ friend class internal::ScopedTrace;
+
+ // Creates an empty UnitTest.
+ UnitTest();
+
+ // D'tor
+ virtual ~UnitTest();
+
+ // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+ // Google Test trace stack.
+ void PushGTestTrace(const internal::TraceInfo& trace);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace();
+
+ // Protects mutable state in *impl_. This is mutable as some const
+ // methods need to lock it too.
+ mutable internal::Mutex mutex_;
+
+ // Opaque implementation object. This field is never changed once
+ // the object is constructed. We don't mark it as const here, as
+ // doing so will cause a warning in the constructor of UnitTest.
+ // Mutable state in *impl_ is protected by mutex_.
+ internal::UnitTestImpl* impl_;
+
+ // We disallow copying UnitTest.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main(). If you use gtest_main, you need to call this before main()
+// starts for it to take effect. For example, you can define a global
+// variable like this:
+//
+// testing::Environment* const foo_env =
+// testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+ return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal {
+
+// These overloaded versions handle ::std::string and ::std::wstring.
+#if GTEST_HAS_STD_STRING
+inline String FormatForFailureMessage(const ::std::string& str) {
+ return (Message() << '"' << str << '"').GetString();
+}
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+inline String FormatForFailureMessage(const ::std::wstring& wstr) {
+ return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+// These overloaded versions handle ::string and ::wstring.
+#if GTEST_HAS_GLOBAL_STRING
+inline String FormatForFailureMessage(const ::string& str) {
+ return (Message() << '"' << str << '"').GetString();
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+inline String FormatForFailureMessage(const ::wstring& wstr) {
+ return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char*, and print it as a C string when it is compared against an
+// std::string object, for example.
+//
+// The default implementation ignores the type of the other operand.
+// Some specialized versions are used to handle formatting wide or
+// narrow C strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+String FormatForComparisonFailureMessage(const T1& value,
+ const T2& /* other_operand */) {
+ return FormatForFailureMessage(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ. The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal. The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+ // This templatized version is for the general case.
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // With this overloaded version, we allow anonymous enums to be used
+ // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+ // enums can be implicitly cast to BiggestInt.
+ //
+ // Even though its body looks the same as the above version, we
+ // cannot merge the two, as it will make anonymous enums unhappy.
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal.
+template <>
+class EqHelper<true> {
+ public:
+ // We define two overloaded versions of Compare(). The first
+ // version will be picked when the second argument to ASSERT_EQ() is
+ // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+ // EXPECT_EQ(false, a_bool).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // This version will be picked when the second argument to
+ // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ T2* actual) {
+ // We already know that 'expected' is a null pointer.
+ return CmpHelperEQ(expected_expression, actual_expression,
+ static_cast<T2*>(NULL), actual);
+ }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ Message msg;\
+ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return AssertionFailure(msg);\
+ }\
+}\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+} // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves. They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+#if GTEST_HAS_STD_STRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+ const char* actual_expression,
+ RawType expected,
+ RawType actual) {
+ const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ StrStream expected_ss;
+ expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << expected;
+
+ StrStream actual_ss;
+ actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << actual;
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ StrStreamToString(&expected_ss),
+ StrStreamToString(&actual_ss),
+ false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class AssertHelper {
+ public:
+ // Constructor.
+ AssertHelper(TestPartResultType type, const char* file, int line,
+ const char* message);
+ // Message assignment is a semantic trick to enable assertion
+ // streaming; see the GTEST_MESSAGE_ macro below.
+ void operator=(const Message& message) const;
+ private:
+ TestPartResultType const type_;
+ const char* const file_;
+ int const line_;
+ String const message_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+} // namespace internal
+
+#ifdef GTEST_HAS_PARAM_TEST
+// The abstract base class that all value-parameterized tests inherit from.
+//
+// This class adds support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+// protected:
+// FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual ~FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual void SetUp() {
+// // Can use GetParam() here.
+// }
+// virtual void TearDown {
+// // Can use GetParam() here.
+// }
+// };
+// TEST_P(FooTest, DoesBar) {
+// // Can use GetParam() method here.
+// Foo foo;
+// ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class TestWithParam : public Test {
+ public:
+ typedef T ParamType;
+
+ // The current parameter value. Is also available in the test fixture's
+ // constructor.
+ const ParamType& GetParam() const { return *parameter_; }
+
+ private:
+ // Sets parameter value. The caller is responsible for making sure the value
+ // remains alive and unchanged throughout the current test.
+ static void SetParam(const ParamType* parameter) {
+ parameter_ = parameter;
+ }
+
+ // Static value used for accessing parameter during a test lifetime.
+ static const ParamType* parameter_;
+
+ // TestClass must be a subclass of TestWithParam<T>.
+ template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* TestWithParam<T>::parameter_ = NULL;
+
+#endif // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied. If not,
+// it behaves like ADD_FAILURE. In particular:
+//
+// EXPECT_TRUE verifies that a Boolean condition is true.
+// EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure. People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+//
+// Examples:
+//
+// EXPECT_TRUE(server.StatusIsOK());
+// ASSERT_FALSE(server.HasPendingRequest(port))
+// << "There are still pending requests " << "on port " << port;
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a fatal failure with a generic message.
+#define FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Generates a success with a generic message.
+#define SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Macros for testing exceptions.
+//
+// * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+// Tests that the statement throws the expected exception.
+// * {ASSERT|EXPECT}_NO_THROW(statement):
+// Tests that the statement doesn't throw any exception.
+// * {ASSERT|EXPECT}_ANY_THROW(statement):
+// Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions.
+#define EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+#include <gtest/gtest_pred_impl.h>
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values. The values must be compatible built-in types,
+// or you will get a compiler error. By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+// 1. It is possible to make a user-defined type work with
+// {ASSERT|EXPECT}_??(), but that requires overloading the
+// comparison operators and is thus discouraged by the Google C++
+// Usage Guide. Therefore, you are advised to use the
+// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+// equal.
+//
+// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+// pointers (in particular, C strings). Therefore, if you use it
+// with two C strings, you are testing how their locations in memory
+// are related, not how their content is related. To compare two C
+// strings by content, use {ASSERT|EXPECT}_STR*().
+//
+// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+// what the actual value is when it fails, and similarly for the
+// other comparisons.
+//
+// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+// evaluate their arguments, which is undefined.
+//
+// 5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+// EXPECT_NE(5, Foo());
+// EXPECT_EQ(NULL, a_pointer);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define EXPECT_NE(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define ASSERT_EQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define ASSERT_NE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define ASSERT_LE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define ASSERT_LT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define ASSERT_GE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define ASSERT_GT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// C String Comparisons. All tests treat NULL and any non-NULL string
+// as different. Two NULLs are equal.
+//
+// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
+// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
+// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+// Tests that two double values are almost equal.
+// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+// Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands. See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2);
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2);
+
+
+#ifdef GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+#define EXPECT_HRESULT_SUCCEEDED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define ASSERT_HRESULT_SUCCEEDED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define EXPECT_HRESULT_FAILED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#define ASSERT_HRESULT_FAILED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+// EXPECT_NO_FATAL_FAILURE(Process());
+// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope. The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, ::testing::Message() << (message))
+
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test". For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro. Example:
+//
+// TEST(FooTest, InitializesCorrectly) {
+// Foo foo;
+// EXPECT_TRUE(foo.StatusIsOK());
+// }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test. This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X. The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code. GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define TEST(test_case_name, test_name)\
+ GTEST_TEST_(test_case_name, test_name,\
+ ::testing::Test, ::testing::internal::GetTestTypeId())
+
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name. The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier. The user should put
+// his test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(0, a_.size());
+// EXPECT_EQ(1, b_.size());
+// }
+
+#define TEST_F(test_fixture, test_name)\
+ GTEST_TEST_(test_fixture, test_name, test_fixture,\
+ ::testing::internal::GetTypeId<test_fixture>())
+
+// Use this macro in main() to run all tests. It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+
+#define RUN_ALL_TESTS()\
+ (::testing::UnitTest::GetInstance()->Run())
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest_pred_impl.h b/utils/unittest/googletest/include/gtest/gtest_pred_impl.h
new file mode 100644
index 000000000000..e1e2f8c4c887
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest_pred_impl.h
@@ -0,0 +1,368 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \
+ ; \
+ else \
+ on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+ const char* e1,
+ Pred pred,
+ const T1& v1) {
+ if (pred(v1)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, v1),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+ #v1, \
+ pred, \
+ v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ Pred pred,
+ const T1& v1,
+ const T2& v2) {
+ if (pred(v1, v2)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+ #v1, \
+ #v2, \
+ pred, \
+ v1, \
+ v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ if (pred(v1, v2, v3)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ pred, \
+ v1, \
+ v2, \
+ v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ", "
+ << e5 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4
+ << "\n" << e5 << " evaluates to " << v5;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ #v5, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4, \
+ v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/utils/unittest/googletest/include/gtest/gtest_prod.h b/utils/unittest/googletest/include/gtest/gtest_prod.h
new file mode 100644
index 000000000000..da80ddc6c70e
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/gtest_prod.h
@@ -0,0 +1,58 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class. For example:
+//
+// class MyClass {
+// private:
+// void MyMethod();
+// FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+// // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h
new file mode 100644
index 000000000000..0769fcaa0e8a
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h
@@ -0,0 +1,201 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status: The integer exit information in the format specified
+// by wait(2)
+// exit code: The integer code passed to exit(3), _exit(2), or
+// returned from main()
+class DeathTest {
+ public:
+ // Create returns false if there was an error determining the
+ // appropriate action to take for the current death test; for example,
+ // if the gtest_death_test_style flag is set to an invalid value.
+ // The LastMessage method will return a more detailed message in that
+ // case. Otherwise, the DeathTest pointer pointed to by the "test"
+ // argument is set. If the death test should be skipped, the pointer
+ // is set to NULL; otherwise, it is set to the address of a new concrete
+ // DeathTest object that controls the execution of the current test.
+ static bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+ DeathTest();
+ virtual ~DeathTest() { }
+
+ // A helper class that aborts a death test when it's deleted.
+ class ReturnSentinel {
+ public:
+ explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+ ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+ private:
+ DeathTest* const test_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+ } GTEST_ATTRIBUTE_UNUSED_;
+
+ // An enumeration of possible roles that may be taken when a death
+ // test is encountered. EXECUTE means that the death test logic should
+ // be executed immediately. OVERSEE means that the program should prepare
+ // the appropriate environment for a child process to execute the death
+ // test, then wait for it to complete.
+ enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+ // An enumeration of the two reasons that a test might be aborted.
+ enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };
+
+ // Assumes one of the above roles.
+ virtual TestRole AssumeRole() = 0;
+
+ // Waits for the death test to finish and returns its status.
+ virtual int Wait() = 0;
+
+ // Returns true if the death test passed; that is, the test process
+ // exited during the test, its exit status matches a user-supplied
+ // predicate, and its stderr output matches a user-supplied regular
+ // expression.
+ // The user-supplied predicate may be a macro expression rather
+ // than a function pointer or functor, or else Wait and Passed could
+ // be combined.
+ virtual bool Passed(bool exit_status_ok) = 0;
+
+ // Signals that the death test did not die as expected.
+ virtual void Abort(AbortReason reason) = 0;
+
+ // Returns a human-readable outcome message regarding the outcome of
+ // the last death test.
+ static const char* LastMessage();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory {
+ public:
+ virtual ~DeathTestFactory() { }
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status);
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (true) { \
+ const ::testing::internal::RE& gtest_regex = (regex); \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
+ __FILE__, __LINE__, &gtest_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != NULL) { \
+ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+ gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel \
+ gtest_sentinel(gtest_dt); \
+ { statement; } \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+ fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// A struct representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+struct InternalRunDeathTestFlag {
+ String file;
+ int line;
+ int index;
+ int status_fd;
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-filepath.h b/utils/unittest/googletest/include/gtest/internal/gtest-filepath.h
new file mode 100644
index 000000000000..9a0682af8b55
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-filepath.h
@@ -0,0 +1,192 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included in testing/base/internal/gtest-internal.h
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class FilePath {
+ public:
+ FilePath() : pathname_("") { }
+ FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+ explicit FilePath(const char* pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ explicit FilePath(const String& pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ FilePath& operator=(const FilePath& rhs) {
+ Set(rhs);
+ return *this;
+ }
+
+ void Set(const FilePath& rhs) {
+ pathname_ = rhs.pathname_;
+ }
+
+ String ToString() const { return pathname_; }
+ const char* c_str() const { return pathname_.c_str(); }
+
+ // Returns the current working directory, or "" if unsuccessful.
+ static FilePath GetCurrentDir();
+
+ // Given directory = "dir", base_name = "test", number = 0,
+ // extension = "xml", returns "dir/test.xml". If number is greater
+ // than zero (e.g., 12), returns "dir/test_12.xml".
+ // On Windows platform, uses \ as the separator rather than /.
+ static FilePath MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension);
+
+ // Returns a pathname for a file that does not currently exist. The pathname
+ // will be directory/base_name.extension or
+ // directory/base_name_<number>.extension if directory/base_name.extension
+ // already exists. The number will be incremented until a pathname is found
+ // that does not already exist.
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+ // There could be a race condition if two or more processes are calling this
+ // function at the same time -- they could both pick the same filename.
+ static FilePath GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension);
+
+ // Returns true iff the path is NULL or "".
+ bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
+
+ // If input name has a trailing separator character, removes it and returns
+ // the name, otherwise return the name string unmodified.
+ // On Windows platform, uses \ as the separator, other platforms use /.
+ FilePath RemoveTrailingPathSeparator() const;
+
+ // Returns a copy of the FilePath with the directory part removed.
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+ // returns an empty FilePath ("").
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveDirectoryName() const;
+
+ // RemoveFileName returns the directory path with the filename removed.
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveFileName() const;
+
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+ // FilePath("dir/file"). If a case-insensitive extension is not
+ // found, returns a copy of the original FilePath.
+ FilePath RemoveExtension(const char* extension) const;
+
+ // Creates directories so that path exists. Returns true if successful or if
+ // the directories already exist; returns false if unable to create
+ // directories for any reason. Will also return false if the FilePath does
+ // not represent a directory (that is, it doesn't end with a path separator).
+ bool CreateDirectoriesRecursively() const;
+
+ // Create the directory so that path exists. Returns true if successful or
+ // if the directory already exists; returns false if unable to create the
+ // directory for any reason, including if the parent directory does not
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
+ bool CreateFolder() const;
+
+ // Returns true if FilePath describes something in the file-system,
+ // either a file, directory, or whatever, and that something exists.
+ bool FileOrDirectoryExists() const;
+
+ // Returns true if pathname describes a directory in the file-system
+ // that exists.
+ bool DirectoryExists() const;
+
+ // Returns true if FilePath ends with a path separator, which indicates that
+ // it is intended to represent a directory. Returns false otherwise.
+ // This does NOT check that a directory (or file) actually exists.
+ bool IsDirectory() const;
+
+ // Returns true if pathname describes a root directory. (Windows has one
+ // root directory per disk drive.)
+ bool IsRootDirectory() const;
+
+ private:
+ // Replaces multiple consecutive separators with a single separator.
+ // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+ // redundancies that might be in a pathname involving "." or "..".
+ //
+ // A pathname with multiple consecutive separators may occur either through
+ // user error or as a result of some scripts or APIs that generate a pathname
+ // with a trailing separator. On other platforms the same API or script
+ // may NOT generate a pathname with a trailing "/". Then elsewhere that
+ // pathname may have another "/" and pathname components added to it,
+ // without checking for the separator already being there.
+ // The script language and operating system may allow paths like "foo//bar"
+ // but some of the functions in FilePath will not handle that correctly. In
+ // particular, RemoveTrailingPathSeparator() only removes one separator, and
+ // it is called in CreateDirectoriesRecursively() assuming that it will change
+ // a pathname from directory syntax (trailing separator) to filename syntax.
+
+ void Normalize();
+
+ String pathname_;
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h
new file mode 100644
index 000000000000..b8f67c186578
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h
@@ -0,0 +1,1267 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION is defined iff the current translation unit is
+// part of Google Test's implementation.
+#ifndef GTEST_IMPLEMENTATION
+// A user is trying to include this from his code - just say no.
+#error "gtest-internal-inl.h is part of Google Test's internal implementation."
+#error "It must not be included except by Google Test itself."
+#endif // GTEST_IMPLEMENTATION
+
+#include <stddef.h>
+
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_OS_WINDOWS
+#include <windows.h> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify these flags in the code, but want
+// Google Test's own unit tests to be able to access them. Therefore we
+// declare them here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(break_on_failure);
+GTEST_DECLARE_bool_(catch_exceptions);
+GTEST_DECLARE_string_(color);
+GTEST_DECLARE_string_(filter);
+GTEST_DECLARE_bool_(list_tests);
+GTEST_DECLARE_string_(output);
+GTEST_DECLARE_bool_(print_time);
+GTEST_DECLARE_int32_(repeat);
+GTEST_DECLARE_int32_(stack_trace_depth);
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRepeatFlag[] = "repeat";
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+ // The c'tor.
+ GTestFlagSaver() {
+ break_on_failure_ = GTEST_FLAG(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+ color_ = GTEST_FLAG(color);
+ death_test_style_ = GTEST_FLAG(death_test_style);
+ filter_ = GTEST_FLAG(filter);
+ internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+ list_tests_ = GTEST_FLAG(list_tests);
+ output_ = GTEST_FLAG(output);
+ print_time_ = GTEST_FLAG(print_time);
+ repeat_ = GTEST_FLAG(repeat);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG(break_on_failure) = break_on_failure_;
+ GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+ GTEST_FLAG(color) = color_;
+ GTEST_FLAG(death_test_style) = death_test_style_;
+ GTEST_FLAG(filter) = filter_;
+ GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+ GTEST_FLAG(list_tests) = list_tests_;
+ GTEST_FLAG(output) = output_;
+ GTEST_FLAG(print_time) = print_time_;
+ GTEST_FLAG(repeat) = repeat_;
+ }
+ private:
+ // Fields for saving the original values of flags.
+ bool break_on_failure_;
+ bool catch_exceptions_;
+ String color_;
+ String death_test_style_;
+ String filter_;
+ String internal_run_death_test_;
+ bool list_tests_;
+ String output_;
+ bool print_time_;
+ bool pretty_;
+ internal::Int32 repeat_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+char* CodePointToUtf8(UInt32 code_point, char* str);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+String WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount();
+
+// List is a simple singly-linked list container.
+//
+// We cannot use std::list as Microsoft's implementation of STL has
+// problems when exception is disabled. There is a hack to work
+// around this, but we've seen cases where the hack fails to work.
+//
+// TODO(wan): switch to std::list when we have a reliable fix for the
+// STL problem, e.g. when we upgrade to the next version of Visual
+// C++, or (more likely) switch to STLport.
+//
+// The element type must support copy constructor.
+
+// Forward declare List
+template <typename E> // E is the element type.
+class List;
+
+// ListNode is a node in a singly-linked list. It consists of an
+// element and a pointer to the next node. The last node in the list
+// has a NULL value for its next pointer.
+template <typename E> // E is the element type.
+class ListNode {
+ friend class List<E>;
+
+ private:
+
+ E element_;
+ ListNode * next_;
+
+ // The c'tor is private s.t. only in the ListNode class and in its
+ // friend class List we can create a ListNode object.
+ //
+ // Creates a node with a given element value. The next pointer is
+ // set to NULL.
+ //
+ // ListNode does NOT have a default constructor. Always use this
+ // constructor (with parameter) to create a ListNode object.
+ explicit ListNode(const E & element) : element_(element), next_(NULL) {}
+
+ // We disallow copying ListNode
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ListNode);
+
+ public:
+
+ // Gets the element in this node.
+ E & element() { return element_; }
+ const E & element() const { return element_; }
+
+ // Gets the next node in the list.
+ ListNode * next() { return next_; }
+ const ListNode * next() const { return next_; }
+};
+
+
+// List is a simple singly-linked list container.
+template <typename E> // E is the element type.
+class List {
+ public:
+
+ // Creates an empty list.
+ List() : head_(NULL), last_(NULL), size_(0) {}
+
+ // D'tor.
+ virtual ~List();
+
+ // Clears the list.
+ void Clear() {
+ if ( size_ > 0 ) {
+ // 1. Deletes every node.
+ ListNode<E> * node = head_;
+ ListNode<E> * next = node->next();
+ for ( ; ; ) {
+ delete node;
+ node = next;
+ if ( node == NULL ) break;
+ next = node->next();
+ }
+
+ // 2. Resets the member variables.
+ head_ = last_ = NULL;
+ size_ = 0;
+ }
+ }
+
+ // Gets the number of elements.
+ int size() const { return size_; }
+
+ // Returns true if the list is empty.
+ bool IsEmpty() const { return size() == 0; }
+
+ // Gets the first element of the list, or NULL if the list is empty.
+ ListNode<E> * Head() { return head_; }
+ const ListNode<E> * Head() const { return head_; }
+
+ // Gets the last element of the list, or NULL if the list is empty.
+ ListNode<E> * Last() { return last_; }
+ const ListNode<E> * Last() const { return last_; }
+
+ // Adds an element to the end of the list. A copy of the element is
+ // created using the copy constructor, and then stored in the list.
+ // Changes made to the element in the list doesn't affect the source
+ // object, and vice versa.
+ void PushBack(const E & element) {
+ ListNode<E> * new_node = new ListNode<E>(element);
+
+ if ( size_ == 0 ) {
+ head_ = last_ = new_node;
+ size_ = 1;
+ } else {
+ last_->next_ = new_node;
+ last_ = new_node;
+ size_++;
+ }
+ }
+
+ // Adds an element to the beginning of this list.
+ void PushFront(const E& element) {
+ ListNode<E>* const new_node = new ListNode<E>(element);
+
+ if ( size_ == 0 ) {
+ head_ = last_ = new_node;
+ size_ = 1;
+ } else {
+ new_node->next_ = head_;
+ head_ = new_node;
+ size_++;
+ }
+ }
+
+ // Removes an element from the beginning of this list. If the
+ // result argument is not NULL, the removed element is stored in the
+ // memory it points to. Otherwise the element is thrown away.
+ // Returns true iff the list wasn't empty before the operation.
+ bool PopFront(E* result) {
+ if (size_ == 0) return false;
+
+ if (result != NULL) {
+ *result = head_->element_;
+ }
+
+ ListNode<E>* const old_head = head_;
+ size_--;
+ if (size_ == 0) {
+ head_ = last_ = NULL;
+ } else {
+ head_ = head_->next_;
+ }
+ delete old_head;
+
+ return true;
+ }
+
+ // Inserts an element after a given node in the list. It's the
+ // caller's responsibility to ensure that the given node is in the
+ // list. If the given node is NULL, inserts the element at the
+ // front of the list.
+ ListNode<E>* InsertAfter(ListNode<E>* node, const E& element) {
+ if (node == NULL) {
+ PushFront(element);
+ return Head();
+ }
+
+ ListNode<E>* const new_node = new ListNode<E>(element);
+ new_node->next_ = node->next_;
+ node->next_ = new_node;
+ size_++;
+ if (node == last_) {
+ last_ = new_node;
+ }
+
+ return new_node;
+ }
+
+ // Returns the number of elements that satisfy a given predicate.
+ // The parameter 'predicate' is a Boolean function or functor that
+ // accepts a 'const E &', where E is the element type.
+ template <typename P> // P is the type of the predicate function/functor
+ int CountIf(P predicate) const {
+ int count = 0;
+ for ( const ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ if ( predicate(node->element()) ) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ // Applies a function/functor to each element in the list. The
+ // parameter 'functor' is a function/functor that accepts a 'const
+ // E &', where E is the element type. This method does not change
+ // the elements.
+ template <typename F> // F is the type of the function/functor
+ void ForEach(F functor) const {
+ for ( const ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ functor(node->element());
+ }
+ }
+
+ // Returns the first node whose element satisfies a given predicate,
+ // or NULL if none is found. The parameter 'predicate' is a
+ // function/functor that accepts a 'const E &', where E is the
+ // element type. This method does not change the elements.
+ template <typename P> // P is the type of the predicate function/functor.
+ const ListNode<E> * FindIf(P predicate) const {
+ for ( const ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ if ( predicate(node->element()) ) {
+ return node;
+ }
+ }
+
+ return NULL;
+ }
+
+ template <typename P>
+ ListNode<E> * FindIf(P predicate) {
+ for ( ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ if ( predicate(node->element() ) ) {
+ return node;
+ }
+ }
+
+ return NULL;
+ }
+
+ private:
+ ListNode<E>* head_; // The first node of the list.
+ ListNode<E>* last_; // The last node of the list.
+ int size_; // The number of elements in the list.
+
+ // We disallow copying List.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(List);
+};
+
+// The virtual destructor of List.
+template <typename E>
+List<E>::~List() {
+ Clear();
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T * x) {
+ delete x;
+}
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+ // C'tor. TestProperty does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestProperty object.
+ TestProperty(const char* key, const char* value) :
+ key_(key), value_(value) {
+ }
+
+ // Gets the user supplied key.
+ const char* key() const {
+ return key_.c_str();
+ }
+
+ // Gets the user supplied value.
+ const char* value() const {
+ return value_.c_str();
+ }
+
+ // Sets a new value, overriding the one supplied in the constructor.
+ void SetValue(const char* new_value) {
+ value_ = new_value;
+ }
+
+ private:
+ // The key supplied by the user.
+ String key_;
+ // The value supplied by the user.
+ String value_;
+};
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+ // Constructor.
+ //
+ // TestPropertyKeyIs has NO default constructor.
+ explicit TestPropertyKeyIs(const char* key)
+ : key_(key) {}
+
+ // Returns true iff the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return String(test_property.key()).Compare(key_) == 0;
+ }
+
+ private:
+ String key_;
+};
+
+// The result of a single Test. This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class TestResult {
+ public:
+ // Creates an empty TestResult.
+ TestResult();
+
+ // D'tor. Do not inherit from TestResult.
+ ~TestResult();
+
+ // Gets the list of TestPartResults.
+ const internal::List<TestPartResult> & test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the list of TestProperties.
+ const internal::List<internal::TestProperty> & test_properties() const {
+ return test_properties_;
+ }
+
+ // Gets the number of successful test parts.
+ int successful_part_count() const;
+
+ // Gets the number of failed test parts.
+ int failed_part_count() const;
+
+ // Gets the number of all test parts. This is the sum of the number
+ // of successful test parts and the number of failed test parts.
+ int total_part_count() const;
+
+ // Returns true iff the test passed (i.e. no test part failed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test failed.
+ bool Failed() const { return failed_part_count() > 0; }
+
+ // Returns true iff the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Sets the elapsed time.
+ void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+ // Adds a test part result to the list.
+ void AddTestPartResult(const TestPartResult& test_part_result);
+
+ // Adds a test property to the list. The property is validated and may add
+ // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+ // key names). If a property is already recorded for the same key, the
+ // value will be updated, rather than storing multiple values for the same
+ // key.
+ void RecordProperty(const internal::TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testcase tags. Returns true if the property is valid.
+ // TODO(russr): Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const internal::TestProperty& test_property);
+
+ // Returns the death test count.
+ int death_test_count() const { return death_test_count_; }
+
+ // Increments the death test count, returning the new count.
+ int increment_death_test_count() { return ++death_test_count_; }
+
+ // Clears the object.
+ void Clear();
+ private:
+ // Protects mutable state of the property list and of owned properties, whose
+ // values may be updated.
+ internal::Mutex test_properites_mutex_;
+
+ // The list of TestPartResults
+ internal::List<TestPartResult> test_part_results_;
+ // The list of TestProperties
+ internal::List<internal::TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+}; // class TestResult
+
+class TestInfoImpl {
+ public:
+ TestInfoImpl(TestInfo* parent, const char* test_case_name,
+ const char* name, const char* test_case_comment,
+ const char* comment, TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+ ~TestInfoImpl();
+
+ // Returns true if this test should run.
+ bool should_run() const { return should_run_; }
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Returns true if this test is disabled. Disabled tests are not run.
+ bool is_disabled() const { return is_disabled_; }
+
+ // Sets the is_disabled member.
+ void set_is_disabled(bool is) { is_disabled_ = is; }
+
+ // Returns the test case name.
+ const char* test_case_name() const { return test_case_name_.c_str(); }
+
+ // Returns the test name.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the test case comment.
+ const char* test_case_comment() const { return test_case_comment_.c_str(); }
+
+ // Returns the test comment.
+ const char* comment() const { return comment_.c_str(); }
+
+ // Returns the ID of the test fixture class.
+ TypeId fixture_class_id() const { return fixture_class_id_; }
+
+ // Returns the test result.
+ internal::TestResult* result() { return &result_; }
+ const internal::TestResult* result() const { return &result_; }
+
+ // Creates the test object, runs it, records its result, and then
+ // deletes it.
+ void Run();
+
+ // Calls the given TestInfo object's Run() method.
+ static void RunTest(TestInfo * test_info) {
+ test_info->impl()->Run();
+ }
+
+ // Clears the test result.
+ void ClearResult() { result_.Clear(); }
+
+ // Clears the test result in the given TestInfo object.
+ static void ClearTestResult(TestInfo * test_info) {
+ test_info->impl()->ClearResult();
+ }
+
+ private:
+ // These fields are immutable properties of the test.
+ TestInfo* const parent_; // The owner of this object
+ const String test_case_name_; // Test case name
+ const String name_; // Test name
+ const String test_case_comment_; // Test case comment
+ const String comment_; // Test comment
+ const TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True iff this test should run
+ bool is_disabled_; // True iff this test is disabled
+ internal::TestFactoryBase* const factory_; // The factory that creates
+ // the test object
+
+ // This field is mutable and needs to be reset before running the
+ // test for the second time.
+ internal::TestResult result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);
+};
+
+} // namespace internal
+
+// A test case, which consists of a list of TestInfos.
+//
+// TestCase is not copyable.
+class TestCase {
+ public:
+ // Creates a TestCase with the given name.
+ //
+ // TestCase does NOT have a default constructor. Always use this
+ // constructor to create a TestCase object.
+ //
+ // Arguments:
+ //
+ // name: name of the test case
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase(const char* name, const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Destructor of TestCase.
+ virtual ~TestCase();
+
+ // Gets the name of the TestCase.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the test case comment.
+ const char* comment() const { return comment_.c_str(); }
+
+ // Returns true if any test in this test case should run.
+ bool should_run() const { return should_run_; }
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Gets the (mutable) list of TestInfos in this TestCase.
+ internal::List<TestInfo*>& test_info_list() { return *test_info_list_; }
+
+ // Gets the (immutable) list of TestInfos in this TestCase.
+ const internal::List<TestInfo *> & test_info_list() const {
+ return *test_info_list_;
+ }
+
+ // Gets the number of successful tests in this test case.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests in this test case.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests in this test case.
+ int disabled_test_count() const;
+
+ // Get the number of tests in this test case that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test case.
+ int total_test_count() const;
+
+ // Returns true iff the test case passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test case failed.
+ bool Failed() const { return failed_test_count() > 0; }
+
+ // Returns the elapsed time, in milliseconds.
+ internal::TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Adds a TestInfo to this test case. Will delete the TestInfo upon
+ // destruction of the TestCase object.
+ void AddTestInfo(TestInfo * test_info);
+
+ // Finds and returns a TestInfo with the given name. If one doesn't
+ // exist, returns NULL.
+ TestInfo* GetTestInfo(const char* test_name);
+
+ // Clears the results of all tests in this test case.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test case.
+ static void ClearTestCaseResult(TestCase* test_case) {
+ test_case->ClearResult();
+ }
+
+ // Runs every test in this TestCase.
+ void Run();
+
+ // Runs every test in the given TestCase.
+ static void RunTestCase(TestCase * test_case) { test_case->Run(); }
+
+ // Returns true iff test passed.
+ static bool TestPassed(const TestInfo * test_info) {
+ const internal::TestInfoImpl* const impl = test_info->impl();
+ return impl->should_run() && impl->result()->Passed();
+ }
+
+ // Returns true iff test failed.
+ static bool TestFailed(const TestInfo * test_info) {
+ const internal::TestInfoImpl* const impl = test_info->impl();
+ return impl->should_run() && impl->result()->Failed();
+ }
+
+ // Returns true iff test is disabled.
+ static bool TestDisabled(const TestInfo * test_info) {
+ return test_info->impl()->is_disabled();
+ }
+
+ // Returns true if the given test should run.
+ static bool ShouldRunTest(const TestInfo *test_info) {
+ return test_info->impl()->should_run();
+ }
+
+ private:
+ // Name of the test case.
+ internal::String name_;
+ // Comment on the test case.
+ internal::String comment_;
+ // List of TestInfos.
+ internal::List<TestInfo*>* test_info_list_;
+ // Pointer to the function that sets up the test case.
+ Test::SetUpTestCaseFunc set_up_tc_;
+ // Pointer to the function that tears down the test case.
+ Test::TearDownTestCaseFunc tear_down_tc_;
+ // True iff any test in this test case should run.
+ bool should_run_;
+ // Elapsed time, in milliseconds.
+ internal::TimeInMillis elapsed_time_;
+
+ // We disallow copying TestCases.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+namespace internal {
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests. It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag. E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter. If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class UnitTestOptions {
+ public:
+ // Functions for processing the gtest_output flag.
+
+ // Returns the output format, or "" for normal printed output.
+ static String GetOutputFormat();
+
+ // Returns the name of the requested output file, or the default if none
+ // was explicitly specified.
+ static String GetOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true iff the wildcard pattern matches the string. The
+ // first ':' or '\0' character in pattern marks the end of it.
+ //
+ // This recursive algorithm isn't very efficient, but is clear and
+ // works well enough for matching test names, which are short.
+ static bool PatternMatchesString(const char *pattern, const char *str);
+
+ // Returns true iff the user-specified filter matches the test case
+ // name and the test name.
+ static bool FilterMatchesTest(const String &test_case_name,
+ const String &test_name);
+
+#ifdef GTEST_OS_WINDOWS
+ // Function for supporting the gtest_catch_exception flag.
+
+ // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+ // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+ // This function is useful as an __except condition.
+ static int GTestShouldProcessSEH(DWORD exception_code);
+#endif // GTEST_OS_WINDOWS
+
+ // Returns true if "name" matches the ':' separated list of glob-style
+ // filters in "filter".
+ static bool MatchesFilter(const String& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present. Used by UnitTestOptions::GetOutputFile.
+FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface() {}
+
+ // Returns the current OS stack trace as a String. Parameters:
+ //
+ // max_depth - the maximum number of stack frames to be included
+ // in the trace.
+ // skip_count - the number of top frames to be skipped; doesn't count
+ // against max_depth.
+ virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+ // UponLeavingGTest() should be called immediately before Google Test calls
+ // user code. It saves some information about the current stack that
+ // CurrentStackTrace() will use to find and hide Google Test stack frames.
+ virtual void UponLeavingGTest() = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetter() {}
+ virtual String CurrentStackTrace(int max_depth, int skip_count);
+ virtual void UponLeavingGTest();
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ Mutex mutex_; // protects all internal state
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to CurrentStackTrace() from within the user code.
+ void* caller_frame_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ String message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. Reports the test part
+ // result in the current test.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. The implementation just
+ // delegates to the current global test part result reporter of *unit_test_.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+};
+
+// The private implementation of the UnitTest class. We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class UnitTestImpl {
+ public:
+ explicit UnitTestImpl(UnitTest* parent);
+ virtual ~UnitTestImpl();
+
+ // There are two different ways to register your own TestPartResultReporter.
+ // You can register your own repoter to listen either only for test results
+ // from the current thread or for results from all threads.
+ // By default, each per-thread test result repoter just passes a new
+ // TestPartResult to the global test result reporter, which registers the
+ // test part result for the currently running test.
+
+ // Returns the global test part result reporter.
+ TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+ // Sets the global test part result reporter.
+ void SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter);
+
+ // Returns the test part result reporter for the current thread.
+ TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+ // Sets the test part result reporter for the current thread.
+ void SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter);
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Returns the TestResult for the test that's currently running, or
+ // the TestResult for the ad hoc test if no test is running.
+ internal::TestResult* current_test_result();
+
+ // Returns the TestResult for the ad hoc test.
+ const internal::TestResult* ad_hoc_test_result() const {
+ return &ad_hoc_test_result_;
+ }
+
+ // Sets the unit test result printer.
+ //
+ // Does nothing if the input and the current printer object are the
+ // same; otherwise, deletes the old printer object and makes the
+ // input the current printer.
+ void set_result_printer(UnitTestEventListenerInterface * result_printer);
+
+ // Returns the current unit test result printer if it is not NULL;
+ // otherwise, creates an appropriate result printer, makes it the
+ // current printer, and returns it.
+ UnitTestEventListenerInterface* result_printer();
+
+ // Sets the OS stack trace getter.
+ //
+ // Does nothing if the input and the current OS stack trace getter
+ // are the same; otherwise, deletes the old getter and makes the
+ // input the current getter.
+ void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+ // Returns the current OS stack trace getter if it is not NULL;
+ // otherwise, creates an OsStackTraceGetter, makes it the current
+ // getter, and returns it.
+ OsStackTraceGetterInterface* os_stack_trace_getter();
+
+ // Returns the current OS stack trace as a String.
+ //
+ // The maximum number of stack frames to be included is specified by
+ // the gtest_stack_trace_depth flag. The skip_count parameter
+ // specifies the number of top frames to be skipped, which doesn't
+ // count against the number of frames to be included.
+ //
+ // For example, if Foo() calls Bar(), which in turn calls
+ // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+ // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+ String CurrentOsStackTraceExceptTop(int skip_count);
+
+ // Finds and returns a TestCase with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_case_name: name of the test case
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase* GetTestCase(const char* test_case_name,
+ const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ // test_info: the TestInfo object
+ void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestInfo * test_info) {
+ // In order to support thread-safe death tests, we need to
+ // remember the original working directory when the test program
+ // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
+ // the user may have changed the current directory before calling
+ // RUN_ALL_TESTS(). Therefore we capture the current directory in
+ // AddTestInfo(), which is called to register a TEST or TEST_F
+ // before main() is reached.
+ if (original_working_dir_.IsEmpty()) {
+ original_working_dir_.Set(FilePath::GetCurrentDir());
+ if (original_working_dir_.IsEmpty()) {
+ printf("%s\n", "Failed to get the current working directory.");
+ abort();
+ }
+ }
+
+ GetTestCase(test_info->test_case_name(),
+ test_info->test_case_comment(),
+ set_up_tc,
+ tear_down_tc)->AddTestInfo(test_info);
+ }
+
+#ifdef GTEST_HAS_PARAM_TEST
+ // Returns ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+ return parameterized_test_registry_;
+ }
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Sets the TestCase object for the test that's currently running.
+ void set_current_test_case(TestCase* current_test_case) {
+ current_test_case_ = current_test_case;
+ }
+
+ // Sets the TestInfo object for the test that's currently running. If
+ // current_test_info is NULL, the assertion results will be stored in
+ // ad_hoc_test_result_.
+ void set_current_test_info(TestInfo* current_test_info) {
+ current_test_info_ = current_test_info;
+ }
+
+ // Registers all parameterized tests defined using TEST_P and
+ // INSTANTIATE_TEST_P, creating regular tests for each test/parameter
+ // combination. This method can be called more then once; it has
+ // guards protecting from registering the tests more then once.
+ // If value-parameterized tests are disabled, RegisterParameterizedTests
+ // is present but does nothing.
+ void RegisterParameterizedTests();
+
+ // Runs all tests in this UnitTest object, prints the result, and
+ // returns 0 if all tests are successful, or 1 otherwise. If any
+ // exception is thrown during a test on Windows, this test is
+ // considered to be failed, but the rest of the tests will still be
+ // run. (We disable exceptions on Linux and Mac OS X, so the issue
+ // doesn't apply there.)
+ int RunAllTests();
+
+ // Clears the results of all tests, including the ad hoc test.
+ void ClearResult() {
+ test_cases_.ForEach(TestCase::ClearTestCaseResult);
+ ad_hoc_test_result_.Clear();
+ }
+
+ // Matches the full name of each test against the user-specified
+ // filter to decide whether the test should run, then records the
+ // result in each TestCase and TestInfo object.
+ // Returns the number of tests that should run.
+ int FilterTests();
+
+ // Lists all the tests by name.
+ void ListAllTests();
+
+ const TestCase* current_test_case() const { return current_test_case_; }
+ TestInfo* current_test_info() { return current_test_info_; }
+ const TestInfo* current_test_info() const { return current_test_info_; }
+
+ // Returns the list of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ internal::List<Environment*>* environments() { return &environments_; }
+ internal::List<Environment*>* environments_in_reverse_order() {
+ return &environments_in_reverse_order_;
+ }
+
+ internal::List<TestCase*>* test_cases() { return &test_cases_; }
+ const internal::List<TestCase*>* test_cases() const { return &test_cases_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ internal::List<TraceInfo>* gtest_trace_stack() {
+ return gtest_trace_stack_.pointer();
+ }
+ const internal::List<TraceInfo>* gtest_trace_stack() const {
+ return gtest_trace_stack_.pointer();
+ }
+
+#ifdef GTEST_HAS_DEATH_TEST
+ // Returns a pointer to the parsed --gtest_internal_run_death_test
+ // flag, or NULL if that flag was not specified.
+ // This information is useful only in a death test child process.
+ const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+ return internal_run_death_test_flag_.get();
+ }
+
+ // Returns a pointer to the current death test factory.
+ internal::DeathTestFactory* death_test_factory() {
+ return death_test_factory_.get();
+ }
+
+ friend class ReplaceDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+
+ private:
+ friend class ::testing::UnitTest;
+
+ // The UnitTest object that owns this implementation object.
+ UnitTest* const parent_;
+
+ // The working directory when the first TEST() or TEST_F() was
+ // executed.
+ internal::FilePath original_working_dir_;
+
+ // The default test part result reporters.
+ DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+ DefaultPerThreadTestPartResultReporter
+ default_per_thread_test_part_result_reporter_;
+
+ // Points to (but doesn't own) the global test part result reporter.
+ TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+ // Protects read and write access to global_test_part_result_reporter_.
+ internal::Mutex global_test_part_result_reporter_mutex_;
+
+ // Points to (but doesn't own) the per-thread test part result reporter.
+ internal::ThreadLocal<TestPartResultReporterInterface*>
+ per_thread_test_part_result_reporter_;
+
+ // The list of environments that need to be set-up/torn-down
+ // before/after the tests are run. environments_in_reverse_order_
+ // simply mirrors environments_ in reverse order.
+ internal::List<Environment*> environments_;
+ internal::List<Environment*> environments_in_reverse_order_;
+
+ internal::List<TestCase*> test_cases_; // The list of TestCases.
+
+#ifdef GTEST_HAS_PARAM_TEST
+ // ParameterizedTestRegistry object used to register value-parameterized
+ // tests.
+ internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+ // Indicates whether RegisterParameterizedTests() has been called already.
+ bool parameterized_tests_registered_;
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Points to the last death test case registered. Initially NULL.
+ internal::ListNode<TestCase*>* last_death_test_case_;
+
+ // This points to the TestCase for the currently running test. It
+ // changes as Google Test goes through one test case after another.
+ // When no test is running, this is set to NULL and Google Test
+ // stores assertion results in ad_hoc_test_result_. Initally NULL.
+ TestCase* current_test_case_;
+
+ // This points to the TestInfo for the currently running test. It
+ // changes as Google Test goes through one test after another. When
+ // no test is running, this is set to NULL and Google Test stores
+ // assertion results in ad_hoc_test_result_. Initially NULL.
+ TestInfo* current_test_info_;
+
+ // Normally, a user only writes assertions inside a TEST or TEST_F,
+ // or inside a function called by a TEST or TEST_F. Since Google
+ // Test keeps track of which test is current running, it can
+ // associate such an assertion with the test it belongs to.
+ //
+ // If an assertion is encountered when no TEST or TEST_F is running,
+ // Google Test attributes the assertion result to an imaginary "ad hoc"
+ // test, and records the result in ad_hoc_test_result_.
+ internal::TestResult ad_hoc_test_result_;
+
+ // The unit test result printer. Will be deleted when the UnitTest
+ // object is destructed. By default, a plain text printer is used,
+ // but the user can set this field to use a custom printer if that
+ // is desired.
+ UnitTestEventListenerInterface* result_printer_;
+
+ // The OS stack trace getter. Will be deleted when the UnitTest
+ // object is destructed. By default, an OsStackTraceGetter is used,
+ // but the user can set this field to use a custom getter if that is
+ // desired.
+ OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+ // How long the test took to run, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+#ifdef GTEST_HAS_DEATH_TEST
+ // The decomposed components of the gtest_internal_run_death_test flag,
+ // parsed when RUN_ALL_TESTS is called.
+ internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<internal::List<TraceInfo> > gtest_trace_stack_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+}; // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+ return UnitTest::GetInstance()->impl();
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
new file mode 100644
index 000000000000..37faaaebea48
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
@@ -0,0 +1,876 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_OS_LINUX
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#include <ctype.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-type-util.h>
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__. Writing
+//
+// foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number. For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+// Google Test defines the testing::Message class to allow construction of
+// test messages via the << operator. The idea is that anything
+// streamable to std::ostream can be streamed to a testing::Message.
+// This allows a user to use his own types in Google Test assertions by
+// overloading the << operator.
+//
+// util/gtl/stl_logging-inl.h overloads << for STL containers. These
+// overloads cannot be defined in the std namespace, as that will be
+// undefined behavior. Therefore, they are defined in the global
+// namespace instead.
+//
+// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+// overloads are visible in either the std namespace or the global
+// namespace, but not other namespaces, including the testing
+// namespace which Google Test's Message class is in.
+//
+// To allow STL containers (and other types that has a << operator
+// defined in the global namespace) to be used in Google Test assertions,
+// testing::Message must access the custom << operator from the global
+// namespace. Hence this helper function.
+//
+// Note: Jeffrey Yasskin suggested an alternative fix by "using
+// ::operator<<;" in the definition of Message's operator<<. That fix
+// doesn't require a helper function, but unfortunately doesn't
+// compile with MSVC.
+template <typename T>
+inline void GTestStreamToHelper(std::ostream* os, const T& val) {
+ *os << val;
+}
+
+namespace testing {
+
+// Forward declaration of classes.
+
+class Message; // Represents a failure message.
+class Test; // Represents a test.
+class TestCase; // A collection of related tests.
+class TestPartResult; // Result of a test part.
+class TestInfo; // Information about a test.
+class UnitTest; // A collection of test cases.
+class UnitTestEventListenerInterface; // Listens to Google Test events.
+class AssertionResult; // Result of an assertion.
+
+namespace internal {
+
+struct TraceInfo; // Information about a trace point.
+class ScopedTrace; // Implements scoped trace.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class TestResult; // Result of a single Test.
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+template <typename E> class List; // A generic list.
+template <typename E> class ListNode; // A node in a generic list.
+
+// How many times InitGoogleTest() has been called.
+extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+extern const char kStackTraceMarker[];
+
+// A secret type that Google Test users don't know about. It has no
+// definition on purpose. Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant). Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler. These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise. Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal. Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2]; // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_COPY_
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler. The Nokia Symbian and the IBM XL C/C++ compiler try to
+// instantiate a copy constructor for objects passed through ellipsis
+// (...), failing for uncopyable objects. Hence we define this to
+// false (and lose support for NULL detection).
+#define GTEST_IS_NULL_LITERAL_(x) false
+#else
+#define GTEST_IS_NULL_LITERAL_(x) \
+ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif // GTEST_ELLIPSIS_NEEDS_COPY_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg);
+
+// A helper class for creating scoped traces in user programs.
+class ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+ ScopedTrace(const char* file, int line, const Message& message);
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
+ // c'tor and d'tor. Therefore it doesn't
+ // need to be used otherwise.
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+// Formats a value to be used in a failure message.
+
+#ifdef GTEST_NEEDS_IS_POINTER_
+
+// These are needed as the Nokia Symbian and IBM XL C/C++ compilers
+// cannot decide between const T& and const T* in a function template.
+// These compilers _can_ decide between class template specializations
+// for T and T*, so a tr1::type_traits-like is_pointer works, and we
+// can overload on that.
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatValueForFailureMessage(internal::true_type dummy,
+ T* pointer) {
+ return StreamableToString(static_cast<const void*>(pointer));
+}
+
+template <typename T>
+inline String FormatValueForFailureMessage(internal::false_type dummy,
+ const T& value) {
+ return StreamableToString(value);
+}
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+ return FormatValueForFailureMessage(
+ typename internal::is_pointer<T>::type(), value);
+}
+
+#else
+
+// These are needed as the above solution using is_pointer has the
+// limitation that T cannot be a type without external linkage, when
+// compiled using MSVC.
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+ return StreamableToString(value);
+}
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatForFailureMessage(T* pointer) {
+ return StreamableToString(static_cast<const void*>(pointer));
+}
+
+#endif // GTEST_NEEDS_IS_POINTER_
+
+// These overloaded versions handle narrow and wide characters.
+String FormatForFailureMessage(char ch);
+String FormatForFailureMessage(wchar_t wchar);
+
+// When this operand is a const char* or char*, and the other operand
+// is a ::std::string or ::string, we print this operand as a C string
+// rather than a pointer. We do the same for wide strings.
+
+// This internal macro is used to avoid duplicated code.
+#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
+inline String FormatForComparisonFailureMessage(\
+ operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
+ return operand1_printer(str);\
+}\
+inline String FormatForComparisonFailureMessage(\
+ const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
+ return operand1_printer(str);\
+}
+
+#if GTEST_HAS_STD_STRING
+GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
+#endif // GTEST_HAS_STD_STRING
+#if GTEST_HAS_STD_WSTRING
+GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_STRING
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#undef GTEST_FORMAT_IMPL_
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case);
+
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison. (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly. Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+// The most-significant bit being the leftmost, an IEEE
+// floating-point looks like
+//
+// sign_bit exponent_bits fraction_bits
+//
+// Here, sign_bit is a single bit that designates the sign of the
+// number.
+//
+// For float, there are 8 exponent bits and 23 fraction bits.
+//
+// For double, there are 11 exponent bits and 52 fraction bits.
+//
+// More details can be found at
+// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+ // Constants.
+
+ // # of bits in a number.
+ static const size_t kBitCount = 8*sizeof(RawType);
+
+ // # of fraction bits in a number.
+ static const size_t kFractionBitCount =
+ std::numeric_limits<RawType>::digits - 1;
+
+ // # of exponent bits in a number.
+ static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+ // The mask for the sign bit.
+ static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask =
+ ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+ // The mask for the exponent bits.
+ static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+ // How many ULP's (Units in the Last Place) we want to tolerate when
+ // comparing two numbers. The larger the value, the more error we
+ // allow. A 0 value means that two numbers must be exactly the same
+ // to be considered equal.
+ //
+ // The maximum error of a single floating-point operation is 0.5
+ // units in the last place. On Intel CPU's, all floating-point
+ // calculations are done with 80-bit precision, while double has 64
+ // bits. Therefore, 4 should be enough for ordinary use.
+ //
+ // See the following article for more details on ULP:
+ // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
+ static const size_t kMaxUlps = 4;
+
+ // Constructs a FloatingPoint from a raw floating-point number.
+ //
+ // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+ // around may change its bits, although the new value is guaranteed
+ // to be also a NAN. Therefore, don't expect this constructor to
+ // preserve the bits in x when x is a NAN.
+ explicit FloatingPoint(const RawType& x) : value_(x) {}
+
+ // Static methods
+
+ // Reinterprets a bit pattern as a floating-point number.
+ //
+ // This function is needed to test the AlmostEquals() method.
+ static RawType ReinterpretBits(const Bits bits) {
+ FloatingPoint fp(0);
+ fp.bits_ = bits;
+ return fp.value_;
+ }
+
+ // Returns the floating-point number that represent positive infinity.
+ static RawType Infinity() {
+ return ReinterpretBits(kExponentBitMask);
+ }
+
+ // Non-static methods
+
+ // Returns the bits that represents this number.
+ const Bits &bits() const { return bits_; }
+
+ // Returns the exponent bits of this number.
+ Bits exponent_bits() const { return kExponentBitMask & bits_; }
+
+ // Returns the fraction bits of this number.
+ Bits fraction_bits() const { return kFractionBitMask & bits_; }
+
+ // Returns the sign bit of this number.
+ Bits sign_bit() const { return kSignBitMask & bits_; }
+
+ // Returns true iff this is NAN (not a number).
+ bool is_nan() const {
+ // It's a NAN if the exponent bits are all ones and the fraction
+ // bits are not entirely zeros.
+ return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+ }
+
+ // Returns true iff this number is at most kMaxUlps ULP's away from
+ // rhs. In particular, this function:
+ //
+ // - returns false if either number is (or both are) NAN.
+ // - treats really large numbers as almost equal to infinity.
+ // - thinks +0.0 and -0.0 are 0 DLP's apart.
+ bool AlmostEquals(const FloatingPoint& rhs) const {
+ // The IEEE standard says that any comparison operation involving
+ // a NAN must return false.
+ if (is_nan() || rhs.is_nan()) return false;
+
+ return DistanceBetweenSignAndMagnitudeNumbers(bits_, rhs.bits_) <= kMaxUlps;
+ }
+
+ private:
+ // Converts an integer from the sign-and-magnitude representation to
+ // the biased representation. More precisely, let N be 2 to the
+ // power of (kBitCount - 1), an integer x is represented by the
+ // unsigned number x + N.
+ //
+ // For instance,
+ //
+ // -N + 1 (the most negative number representable using
+ // sign-and-magnitude) is represented by 1;
+ // 0 is represented by N; and
+ // N - 1 (the biggest number representable using
+ // sign-and-magnitude) is represented by 2N - 1.
+ //
+ // Read http://en.wikipedia.org/wiki/Signed_number_representations
+ // for more details on signed number representations.
+ static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+ if (kSignBitMask & sam) {
+ // sam represents a negative number.
+ return ~sam + 1;
+ } else {
+ // sam represents a positive number.
+ return kSignBitMask | sam;
+ }
+ }
+
+ // Given two numbers in the sign-and-magnitude representation,
+ // returns the distance between them as an unsigned number.
+ static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+ const Bits &sam2) {
+ const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+ const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+ return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+ }
+
+ union {
+ RawType value_; // The raw floating-point number.
+ Bits bits_; // The bits that represent the number.
+ };
+};
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them. The TypeId type is
+// used to hold such IDs. The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+ // dummy_ must not have a const type. Otherwise an overly eager
+ // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+ // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+ static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T. Different values will be
+// returned for different types. Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+ // The compiler is required to allocate a different
+ // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+ // the template. Therefore, the address of dummy_ is guaranteed to
+ // be unique.
+ return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test. Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+ virtual ~TestFactoryBase() {}
+
+ // Creates a test instance to run. The instance is both created and destroyed
+ // within TestInfoImpl::Run()
+ virtual Test* CreateTest() = 0;
+
+ protected:
+ TestFactoryBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+ virtual Test* CreateTest() { return new TestClass; }
+};
+
+#ifdef GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT
+AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT
+
+#endif // GTEST_OS_WINDOWS
+
+// Formats a source file path and a line number as they would appear
+// in a compiler error message.
+inline String FormatFileLocation(const char* file, int line) {
+ const char* const file_name = file == NULL ? "unknown file" : file;
+ if (line < 0) {
+ return String::Format("%s:", file_name);
+ }
+#ifdef _MSC_VER
+ return String::Format("%s(%d):", file_name, line);
+#else
+ return String::Format("%s:%d:", file_name, line);
+#endif // _MSC_VER
+}
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// test_case_comment: a comment on the test case that will be included in
+// the test output
+// comment: a comment on the test that will be included in the
+// test output
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory);
+
+#if defined(GTEST_HAS_TYPED_TEST) || defined(GTEST_HAS_TYPED_TEST_P)
+
+// State of the definition of a type-parameterized test case.
+class TypedTestCasePState {
+ public:
+ TypedTestCasePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test case hasn't been registered; otherwise aborts the
+ // program.
+ bool AddTestName(const char* file, int line, const char* case_name,
+ const char* test_name) {
+ if (registered_) {
+ fprintf(stderr, "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ abort();
+ }
+ defined_test_names_.insert(test_name);
+ return true;
+ }
+
+ // Verifies that registered_tests match the test names in
+ // defined_test_names_; returns registered_tests if successful, or
+ // aborts the program otherwise.
+ const char* VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests);
+
+ private:
+ bool registered_;
+ ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ if (comma == NULL) {
+ return NULL;
+ }
+ while (isspace(*(++comma))) {}
+ return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline String GetPrefixUntilComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ return comma == NULL ? String(str) : String(str, comma - str);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test. The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter. It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+ // Types). Valid values for 'index' are [0, N - 1] where N is the
+ // length of Types.
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names, int index) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
+ case_name, index).c_str(),
+ GetPrefixUntilComma(test_names).c_str(),
+ String::Format("TypeParam = %s", GetTypeName<Type>().c_str()).c_str(),
+ "",
+ GetTypeId<FixtureClass>(),
+ TestClass::SetUpTestCase,
+ TestClass::TearDownTestCase,
+ new TestFactoryImpl<TestClass>);
+
+ // Next, recurses (at compile time) with the tail of the type list.
+ return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+ ::Register(prefix, case_name, test_names, index + 1);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/, int /*index*/) {
+ return true;
+ }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test. The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, case_name, test_names, 0);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+ ::Register(prefix, case_name, SkipComma(test_names));
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ return true;
+ }
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count);
+
+// Returns the number of failed test parts in the given test result object.
+int GetFailedPartCount(const TestResult* result);
+
+} // namespace internal
+} // namespace testing
+
+#define GTEST_MESSAGE_(message, result_type) \
+ ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \
+ = ::testing::Message()
+
+#define GTEST_FATAL_FAILURE_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TPRT_FATAL_FAILURE)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+ GTEST_MESSAGE_(message, ::testing::TPRT_NONFATAL_FAILURE)
+
+#define GTEST_SUCCESS_(message) \
+ GTEST_MESSAGE_(message, ::testing::TPRT_SUCCESS)
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ bool gtest_caught_expected = false; \
+ try { \
+ statement; \
+ } \
+ catch (expected_exception const&) { \
+ gtest_caught_expected = true; \
+ } \
+ catch (...) { \
+ gtest_msg = "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws a different " \
+ "type."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ if (!gtest_caught_expected) { \
+ gtest_msg = "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws nothing."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+ fail(gtest_msg)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ try { \
+ statement; \
+ } \
+ catch (...) { \
+ gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \
+ " Actual: it throws."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+ fail(gtest_msg)
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ bool gtest_caught_any = false; \
+ try { \
+ statement; \
+ } \
+ catch (...) { \
+ gtest_caught_any = true; \
+ } \
+ if (!gtest_caught_any) { \
+ gtest_msg = "Expected: " #statement " throws an exception.\n" \
+ " Actual: it doesn't."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+ fail(gtest_msg)
+
+
+#define GTEST_TEST_BOOLEAN_(boolexpr, booltext, actual, expected, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (boolexpr) \
+ ; \
+ else \
+ fail("Value of: " booltext "\n Actual: " #actual "\nExpected: " #expected)
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+ { statement; } \
+ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+ gtest_msg = "Expected: " #statement " doesn't generate new fatal " \
+ "failures in the current thread.\n" \
+ " Actual: it does."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+ fail(gtest_msg)
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+ virtual void TestBody();\
+ static ::testing::TestInfo* const test_info_;\
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+ ::test_info_ =\
+ ::testing::internal::MakeAndRegisterTestInfo(\
+ #test_case_name, #test_name, "", "", \
+ (parent_id), \
+ parent_class::SetUpTestCase, \
+ parent_class::TearDownTestCase, \
+ new ::testing::internal::TestFactoryImpl<\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h b/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h
new file mode 100644
index 000000000000..f98af0b123bd
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h
@@ -0,0 +1,242 @@
+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor@google.com)
+//
+// A "smart" pointer type with reference tracking. Every pointer to a
+// particular object is kept on a circular linked list. When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+// object is traversed. This class is therefore NOT SUITABLE when there
+// will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+// will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+// Unlike other linked_ptr implementations, in this implementation
+// a linked_ptr object is thread-safe in the sense that:
+// - it's safe to copy linked_ptr objects concurrently,
+// - it's safe to copy *from* a linked_ptr and read its underlying
+// raw pointer (e.g. via get()) concurrently, and
+// - it's safe to write to two linked_ptrs that point to the same
+// shared object concurrently.
+// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <gtest/internal/gtest-port.h>
+
+namespace testing {
+namespace internal {
+
+// Protects copying of all linked_ptr objects.
+extern Mutex g_linked_ptr_mutex;
+
+// This is used internally by all instances of linked_ptr<>. It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+ // Create a new circle that includes only this instance.
+ void join_new() {
+ next_ = this;
+ }
+
+ // Many linked_ptr operations may change p.link_ for some linked_ptr
+ // variable p in the same circle as this object. Therefore we need
+ // to prevent two such operations from occurring concurrently.
+ //
+ // Note that different types of linked_ptr objects can coexist in a
+ // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+ // linked_ptr<Derived2>). Therefore we must use a single mutex to
+ // protect all linked_ptr objects. This can create serious
+ // contention in production code, but is acceptable in a testing
+ // framework.
+
+ // Join an existing circle.
+ // L < g_linked_ptr_mutex
+ void join(linked_ptr_internal const* ptr) {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ linked_ptr_internal const* p = ptr;
+ while (p->next_ != ptr) p = p->next_;
+ p->next_ = this;
+ next_ = ptr;
+ }
+
+ // Leave whatever circle we're part of. Returns true if we were the
+ // last member of the circle. Once this is done, you can join() another.
+ // L < g_linked_ptr_mutex
+ bool depart() {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ if (next_ == this) return true;
+ linked_ptr_internal const* p = next_;
+ while (p->next_ != this) p = p->next_;
+ p->next_ = next_;
+ return false;
+ }
+
+ private:
+ mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+ typedef T element_type;
+
+ // Take over ownership of a raw pointer. This should happen as soon as
+ // possible after the object is created.
+ explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+ ~linked_ptr() { depart(); }
+
+ // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+ template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+ linked_ptr(linked_ptr const& ptr) { // NOLINT
+ assert(&ptr != this);
+ copy(&ptr);
+ }
+
+ // Assignment releases the old value and acquires the new.
+ template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+ depart();
+ copy(&ptr);
+ return *this;
+ }
+
+ linked_ptr& operator=(linked_ptr const& ptr) {
+ if (&ptr != this) {
+ depart();
+ copy(&ptr);
+ }
+ return *this;
+ }
+
+ // Smart pointer members.
+ void reset(T* ptr = NULL) {
+ depart();
+ capture(ptr);
+ }
+ T* get() const { return value_; }
+ T* operator->() const { return value_; }
+ T& operator*() const { return *value_; }
+ // Release ownership of the pointed object and returns it.
+ // Sole ownership by this linked_ptr object is required.
+ T* release() {
+ bool last = link_.depart();
+ assert(last);
+ T* v = value_;
+ value_ = NULL;
+ return v;
+ }
+
+ bool operator==(T* p) const { return value_ == p; }
+ bool operator!=(T* p) const { return value_ != p; }
+ template <typename U>
+ bool operator==(linked_ptr<U> const& ptr) const {
+ return value_ == ptr.get();
+ }
+ template <typename U>
+ bool operator!=(linked_ptr<U> const& ptr) const {
+ return value_ != ptr.get();
+ }
+
+ private:
+ template <typename U>
+ friend class linked_ptr;
+
+ T* value_;
+ linked_ptr_internal link_;
+
+ void depart() {
+ if (link_.depart()) delete value_;
+ }
+
+ void capture(T* ptr) {
+ value_ = ptr;
+ link_.join_new();
+ }
+
+ template <typename U> void copy(linked_ptr<U> const* ptr) {
+ value_ = ptr->get();
+ if (value_)
+ link_.join(&ptr->link_);
+ else
+ link_.join_new();
+ }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+ return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+ return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+ return linked_ptr<T>(ptr);
+}
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h
new file mode 100644
index 000000000000..17f3f7bf97da
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h
@@ -0,0 +1,4572 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework@googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_HAS_PARAM_TEST
+
+#include <gtest/internal/gtest-param-util.h>
+
+namespace testing {
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+ explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+ const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2 {
+ public:
+ ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3 {
+ public:
+ ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4 {
+ public:
+ ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5 {
+ public:
+ ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class ValueArray6 {
+ public:
+ ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class ValueArray7 {
+ public:
+ ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class ValueArray8 {
+ public:
+ ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class ValueArray9 {
+ public:
+ ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10 {
+ public:
+ ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+class ValueArray11 {
+ public:
+ ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+class ValueArray12 {
+ public:
+ ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+class ValueArray13 {
+ public:
+ ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+class ValueArray14 {
+ public:
+ ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15 {
+ public:
+ ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+class ValueArray16 {
+ public:
+ ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+class ValueArray17 {
+ public:
+ ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+class ValueArray18 {
+ public:
+ ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+class ValueArray19 {
+ public:
+ ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20 {
+ public:
+ ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+class ValueArray21 {
+ public:
+ ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+class ValueArray22 {
+ public:
+ ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+class ValueArray23 {
+ public:
+ ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,
+ v23_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+class ValueArray24 {
+ public:
+ ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25 {
+ public:
+ ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+class ValueArray26 {
+ public:
+ ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+class ValueArray27 {
+ public:
+ ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+class ValueArray28 {
+ public:
+ ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+class ValueArray29 {
+ public:
+ ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30 {
+ public:
+ ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+class ValueArray31 {
+ public:
+ ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+class ValueArray32 {
+ public:
+ ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+class ValueArray33 {
+ public:
+ ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+class ValueArray34 {
+ public:
+ ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35 {
+ public:
+ ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,
+ v35_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+class ValueArray36 {
+ public:
+ ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+class ValueArray37 {
+ public:
+ ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+class ValueArray38 {
+ public:
+ ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+class ValueArray39 {
+ public:
+ ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40 {
+ public:
+ ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+class ValueArray41 {
+ public:
+ ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+class ValueArray42 {
+ public:
+ ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+class ValueArray43 {
+ public:
+ ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+ v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+class ValueArray44 {
+ public:
+ ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+ v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+ v43_(v43), v44_(v44) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45 {
+ public:
+ ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+ v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+class ValueArray46 {
+ public:
+ ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+class ValueArray47 {
+ public:
+ ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+ v47_(v47) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,
+ v47_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+class ValueArray48 {
+ public:
+ ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+ v46_(v46), v47_(v47), v48_(v48) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+class ValueArray49 {
+ public:
+ ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+ T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_, v49_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50 {
+ public:
+ ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+ T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_, v49_, v50_};
+ return ValuesIn(array);
+ }
+
+ private:
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+ const T50 v50_;
+};
+
+#ifdef GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+ CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2)
+ : g1_(g1), g2_(g2) {}
+ virtual ~CartesianProductGenerator2() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current2_;
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+};
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+ CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ virtual ~CartesianProductGenerator3() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current3_;
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+ CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ virtual ~CartesianProductGenerator4() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current4_;
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+ CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ virtual ~CartesianProductGenerator5() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current5_;
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class CartesianProductGenerator6
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+ T6> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+ CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ virtual ~CartesianProductGenerator6() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current6_;
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class CartesianProductGenerator7
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+ CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ virtual ~CartesianProductGenerator7() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current7_;
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+ CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ virtual ~CartesianProductGenerator8() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current8_;
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+ CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ virtual ~CartesianProductGenerator9() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current9_;
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9, T10> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+ CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+ const ParamGenerator<T10>& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ virtual ~CartesianProductGenerator10() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9,
+ const ParamGenerator<T10>& g10,
+ const typename ParamGenerator<T10>::iterator& current10)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+ begin10_(g10.begin()), end10_(g10.end()), current10_(current10) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current10_;
+ if (current10_ == end10_) {
+ current10_ = begin10_;
+ ++current9_;
+ }
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_ &&
+ current10_ == typed_other->current10_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_),
+ begin10_(other.begin10_),
+ end10_(other.end10_),
+ current10_(other.current10_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_, *current10_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_ ||
+ current10_ == end10_;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ const typename ParamGenerator<T10>::iterator begin10_;
+ const typename ParamGenerator<T10>::iterator end10_;
+ typename ParamGenerator<T10>::iterator current10_;
+ ParamType current_value_;
+ };
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+ const ParamGenerator<T10> g10_;
+};
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2 {
+ public:
+CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+ : g1_(g1), g2_(g2) {}
+ template <typename T1, typename T2>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+ new CartesianProductGenerator2<T1, T2>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+};
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3 {
+ public:
+CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ template <typename T1, typename T2, typename T3>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+ new CartesianProductGenerator3<T1, T2, T3>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4>
+class CartesianProductHolder4 {
+ public:
+CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ template <typename T1, typename T2, typename T3, typename T4>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+ new CartesianProductGenerator4<T1, T2, T3, T4>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5>
+class CartesianProductHolder5 {
+ public:
+CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+ new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6 {
+ public:
+CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+ new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7 {
+ public:
+CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+ new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8>
+class CartesianProductHolder8 {
+ public:
+CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+ T8> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+ new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9>
+class CartesianProductHolder9 {
+ public:
+CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >(
+ new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10 {
+ public:
+CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9, const Generator10& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >(
+ new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+ T10>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_),
+ static_cast<ParamGenerator<T10> >(g10_)));
+ }
+
+ private:
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+ const Generator10 g10_;
+};
+
+#endif // GTEST_HAS_COMBINE
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h
new file mode 100644
index 000000000000..3bb07ecfc01f
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h
@@ -0,0 +1,629 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_HAS_PARAM_TEST
+
+#if GTEST_HAS_RTTI
+#include <typeinfo>
+#endif // GTEST_HAS_RTTI
+
+#include <gtest/internal/gtest-linked_ptr.h>
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+ GTEST_CHECK_(typeid(*base) == typeid(Derived));
+ Derived* derived = dynamic_cast<Derived*>(base); // NOLINT
+#else
+ Derived* derived = static_cast<Derived*>(base); // Poor man's downcast.
+#endif // GTEST_HAS_RTTI
+ return derived;
+}
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+ virtual ~ParamIteratorInterface() {}
+ // A pointer to the base generator instance.
+ // Used only for the purposes of iterator comparison
+ // to make sure that two iterators belong to the same generator.
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+ // Advances iterator to point to the next element
+ // provided by the generator. The caller is responsible
+ // for not calling Advance() on an iterator equal to
+ // BaseGenerator()->End().
+ virtual void Advance() = 0;
+ // Clones the iterator object. Used for implementing copy semantics
+ // of ParamIterator<T>.
+ virtual ParamIteratorInterface* Clone() const = 0;
+ // Dereferences the current iterator and provides (read-only) access
+ // to the pointed value. It is the caller's responsibility not to call
+ // Current() on an iterator equal to BaseGenerator()->End().
+ // Used for implementing ParamGenerator<T>::operator*().
+ virtual const T* Current() const = 0;
+ // Determines whether the given iterator and other point to the same
+ // element in the sequence generated by the generator.
+ // Used for implementing ParamGenerator<T>::operator==().
+ virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+ typedef T value_type;
+ typedef const T& reference;
+ typedef ptrdiff_t difference_type;
+
+ // ParamIterator assumes ownership of the impl_ pointer.
+ ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+ ParamIterator& operator=(const ParamIterator& other) {
+ if (this != &other)
+ impl_.reset(other.impl_->Clone());
+ return *this;
+ }
+
+ const T& operator*() const { return *impl_->Current(); }
+ const T* operator->() const { return impl_->Current(); }
+ // Prefix version of operator++.
+ ParamIterator& operator++() {
+ impl_->Advance();
+ return *this;
+ }
+ // Postfix version of operator++.
+ ParamIterator operator++(int /*unused*/) {
+ ParamIteratorInterface<T>* clone = impl_->Clone();
+ impl_->Advance();
+ return ParamIterator(clone);
+ }
+ bool operator==(const ParamIterator& other) const {
+ return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+ }
+ bool operator!=(const ParamIterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend class ParamGenerator<T>;
+ explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+ scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+ typedef T ParamType;
+
+ virtual ~ParamGeneratorInterface() {}
+
+ // Generator interface definition
+ virtual ParamIteratorInterface<T>* Begin() const = 0;
+ virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInetrface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+ typedef ParamIterator<T> iterator;
+
+ explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+ ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+ ParamGenerator& operator=(const ParamGenerator& other) {
+ impl_ = other.impl_;
+ return *this;
+ }
+
+ iterator begin() const { return iterator(impl_->Begin()); }
+ iterator end() const { return iterator(impl_->End()); }
+
+ private:
+ ::testing::internal::linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ RangeGenerator(T begin, T end, IncrementT step)
+ : begin_(begin), end_(end),
+ step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+ virtual ~RangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, begin_, 0, step_);
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, end_, end_index_, step_);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+ IncrementT step)
+ : base_(base), value_(value), index_(index), step_(step) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ value_ = value_ + step_;
+ index_++;
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const T* Current() const { return &value_; }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const int other_index =
+ CheckedDowncastToActualType<const Iterator>(&other)->index_;
+ return index_ == other_index;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_), value_(other.value_), index_(other.index_),
+ step_(other.step_) {}
+
+ const ParamGeneratorInterface<T>* const base_;
+ T value_;
+ int index_;
+ const IncrementT step_;
+ }; // class RangeGenerator::Iterator
+
+ static int CalculateEndIndex(const T& begin,
+ const T& end,
+ const IncrementT& step) {
+ int end_index = 0;
+ for (T i = begin; i < end; i = i + step)
+ end_index++;
+ return end_index;
+ }
+
+ const T begin_;
+ const T end_;
+ const IncrementT step_;
+ // The index for the end() iterator. All the elements in the generated
+ // sequence are indexed (0-based) to aid iterator comparison.
+ const int end_index_;
+}; // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ template <typename ForwardIterator>
+ ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+ : container_(begin, end) {}
+ virtual ~ValuesInIteratorRangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, container_.begin());
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, container_.end());
+ }
+
+ private:
+ typedef typename ::std::vector<T> ContainerType;
+
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base,
+ typename ContainerType::const_iterator iterator)
+ : base_(base), iterator_(iterator) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ ++iterator_;
+ value_.reset();
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ // We need to use cached value referenced by iterator_ because *iterator_
+ // can return a temporary object (and of type other then T), so just
+ // having "return &*iterator_;" doesn't work.
+ // value_ is updated here and not in Advance() because Advance()
+ // can advance iterator_ beyond the end of the range, and we cannot
+ // detect that fact. The client code, on the other hand, is
+ // responsible for not calling Current() on an out-of-range iterator.
+ virtual const T* Current() const {
+ if (value_.get() == NULL)
+ value_.reset(new T(*iterator_));
+ return value_.get();
+ }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ return iterator_ ==
+ CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ // The explicit constructor call suppresses a false warning
+ // emitted by gcc when supplied with the -Wextra option.
+ : ParamIteratorInterface<T>(),
+ base_(other.base_),
+ iterator_(other.iterator_) {}
+
+ const ParamGeneratorInterface<T>* const base_;
+ typename ContainerType::const_iterator iterator_;
+ // A cached value of *iterator_. We keep it here to allow access by
+ // pointer in the wrapping iterator's operator->().
+ // value_ needs to be mutable to be accessed in Current().
+ // Use of scoped_ptr helps manage cached value's lifetime,
+ // which is bound by the lifespan of the iterator itself.
+ mutable scoped_ptr<const T> value_;
+ };
+
+ const ContainerType container_;
+}; // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+ typedef typename TestClass::ParamType ParamType;
+ explicit ParameterizedTestFactory(ParamType parameter) :
+ parameter_(parameter) {}
+ virtual Test* CreateTest() {
+ TestClass::SetParam(&parameter_);
+ return new TestClass();
+ }
+
+ private:
+ const ParamType parameter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+ virtual ~TestMetaFactoryBase() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+ : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ public:
+ typedef typename TestCase::ParamType ParamType;
+
+ TestMetaFactory() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+ return new ParameterizedTestFactory<TestCase>(parameter);
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase {
+ public:
+ virtual ~ParameterizedTestCaseInfoBase() {}
+
+ // Base part of test case name for display purposes.
+ virtual const String& GetTestCaseName() const = 0;
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const = 0;
+ // UnitTest class invokes this method to register tests in this
+ // test case right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ virtual void RegisterTests() = 0;
+
+ protected:
+ ParameterizedTestCaseInfoBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+ public:
+ // ParamType and GeneratorCreationFunc are private types but are required
+ // for declarations of public methods AddTestPattern() and
+ // AddTestCaseInstantiation().
+ typedef typename TestCase::ParamType ParamType;
+ // A function that returns an instance of appropriate generator type.
+ typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+ explicit ParameterizedTestCaseInfo(const char* name)
+ : test_case_name_(name) {}
+
+ // Test case base name for display purposes.
+ virtual const String& GetTestCaseName() const { return test_case_name_; }
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+ // TEST_P macro uses AddTestPattern() to record information
+ // about a single test in a LocalTestInfo structure.
+ // test_case_name is the base name of the test case (without invocation
+ // prefix). test_base_name is the name of an individual test without
+ // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+ // test case base name and DoBar is test base name.
+ void AddTestPattern(const char* test_case_name,
+ const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* meta_factory) {
+ tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+ test_base_name,
+ meta_factory)));
+ }
+ // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+ // about a generator.
+ int AddTestCaseInstantiation(const char* instantiation_name,
+ GeneratorCreationFunc* func,
+ const char* file,
+ int line) {
+ instantiations_.push_back(::std::make_pair(instantiation_name, func));
+ return 0; // Return value used only to run this method in namespace scope.
+ }
+ // UnitTest class invokes this method to register tests in this test case
+ // test cases right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more then once.
+ virtual void RegisterTests() {
+ for (typename TestInfoContainer::iterator test_it = tests_.begin();
+ test_it != tests_.end(); ++test_it) {
+ linked_ptr<TestInfo> test_info = *test_it;
+ for (typename InstantiationContainer::iterator gen_it =
+ instantiations_.begin(); gen_it != instantiations_.end();
+ ++gen_it) {
+ const String& instantiation_name = gen_it->first;
+ ParamGenerator<ParamType> generator((*gen_it->second)());
+
+ Message test_case_name_stream;
+ if ( !instantiation_name.empty() )
+ test_case_name_stream << instantiation_name.c_str() << "/";
+ test_case_name_stream << test_info->test_case_base_name.c_str();
+
+ int i = 0;
+ for (typename ParamGenerator<ParamType>::iterator param_it =
+ generator.begin();
+ param_it != generator.end(); ++param_it, ++i) {
+ Message test_name_stream;
+ test_name_stream << test_info->test_base_name.c_str() << "/" << i;
+ ::testing::internal::MakeAndRegisterTestInfo(
+ test_case_name_stream.GetString().c_str(),
+ test_name_stream.GetString().c_str(),
+ "", // test_case_comment
+ "", // comment; TODO(vladl@google.com): provide parameter value
+ // representation.
+ GetTestCaseTypeId(),
+ TestCase::SetUpTestCase,
+ TestCase::TearDownTestCase,
+ test_info->test_meta_factory->CreateTestFactory(*param_it));
+ } // for param_it
+ } // for gen_it
+ } // for test_it
+ } // RegisterTests
+
+ private:
+ // LocalTestInfo structure keeps information about a single test registered
+ // with TEST_P macro.
+ struct TestInfo {
+ TestInfo(const char* test_case_base_name,
+ const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* test_meta_factory) :
+ test_case_base_name(test_case_base_name),
+ test_base_name(test_base_name),
+ test_meta_factory(test_meta_factory) {}
+
+ const String test_case_base_name;
+ const String test_base_name;
+ const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+ };
+ typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+ // Keeps pairs of <Instantiation name, Sequence generator creation function>
+ // received from INSTANTIATE_TEST_CASE_P macros.
+ typedef ::std::vector<std::pair<String, GeneratorCreationFunc*> >
+ InstantiationContainer;
+
+ const String test_case_name_;
+ TestInfoContainer tests_;
+ InstantiationContainer instantiations_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+}; // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry {
+ public:
+ ParameterizedTestCaseRegistry() {}
+ ~ParameterizedTestCaseRegistry() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ // Looks up or creates and returns a structure containing information about
+ // tests and instantiations of a particular test case.
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name,
+ const char* file,
+ int line) {
+ ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ if ((*it)->GetTestCaseName() == test_case_name) {
+ if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+ // Complain about incorrect usage of Google Test facilities
+ // and terminate the program since we cannot guaranty correct
+ // test case setup and tear-down in this case.
+ ReportInvalidTestCaseType(test_case_name, file, line);
+ abort();
+ } else {
+ // At this point we are sure that the object we found is of the same
+ // type we are looking for, so we downcast it to that type
+ // without further checks.
+ typed_test_info = CheckedDowncastToActualType<
+ ParameterizedTestCaseInfo<TestCase> >(*it);
+ }
+ break;
+ }
+ }
+ if (typed_test_info == NULL) {
+ typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+ test_case_infos_.push_back(typed_test_info);
+ }
+ return typed_test_info;
+ }
+ void RegisterTests() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ (*it)->RegisterTests();
+ }
+ }
+
+ private:
+ typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+ TestCaseInfoContainer test_case_infos_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
new file mode 100644
index 000000000000..6a1593ef0178
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
@@ -0,0 +1,862 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms. They are subject to change without notice. DO NOT USE
+// THEM IN USER CODE.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior. If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
+// is/isn't available.
+// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::string, which is different to std::string).
+// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::wstring, which is different to std::wstring).
+// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
+// is/isn't available.
+// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
+// enabled.
+// GTEST_HAS_STD_STRING - Define it to 1/0 to indicate that
+// std::string does/doesn't work (Google Test can
+// be used where std::string is unavailable).
+// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
+// std::wstring does/doesn't work (Google Test can
+// be used where std::wstring is unavailable).
+// GTEST_HAS_TR1_TUPLE 1 - Define it to 1/0 to indicate tr1::tuple
+// is/isn't available.
+
+// This header defines the following utilities:
+//
+// Macros indicating the name of the Google C++ Testing Framework project:
+// GTEST_NAME - a string literal of the project name.
+// GTEST_FLAG_PREFIX - a string literal of the prefix all Google
+// Test flag names share.
+// GTEST_FLAG_PREFIX_UPPER - a string literal of the prefix all Google
+// Test flag names share, in upper case.
+//
+// Macros indicating the current platform:
+// GTEST_OS_CYGWIN - defined iff compiled on Cygwin.
+// GTEST_OS_LINUX - defined iff compiled on Linux.
+// GTEST_OS_MAC - defined iff compiled on Mac OS X.
+// GTEST_OS_SOLARIS - defined iff compiled on Sun Solaris.
+// GTEST_OS_SYMBIAN - defined iff compiled for Symbian.
+// GTEST_OS_WINDOWS - defined iff compiled on Windows.
+// GTEST_OS_ZOS - defined iff compiled on IBM z/OS.
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support. Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable. If you notice any problems on your platform, please notify
+// googletestframework@googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_ macros are defined.
+//
+// Macros indicating available Google Test features:
+// GTEST_HAS_COMBINE - defined iff Combine construct is supported
+// in value-parameterized tests.
+// GTEST_HAS_DEATH_TEST - defined iff death tests are supported.
+// GTEST_HAS_PARAM_TEST - defined iff value-parameterized tests are
+// supported.
+// GTEST_HAS_TYPED_TEST - defined iff typed tests are supported.
+// GTEST_HAS_TYPED_TEST_P - defined iff type-parameterized tests are
+// supported.
+//
+// Macros for basic C++ coding:
+// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances don't have to
+// be used.
+// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+// synchronization primitives have real implementations
+// and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
+//
+// Smart pointers:
+// scoped_ptr - as in TR2.
+//
+// Regular expressions:
+// RE - a simple regular expression class using the POSIX
+// Extended Regular Expression syntax. Not available on
+// Windows.
+//
+// Logging:
+// GTEST_LOG_() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+//
+// Stderr capturing:
+// CaptureStderr() - starts capturing stderr.
+// GetCapturedStderr() - stops capturing stderr and returns the captured
+// string.
+//
+// Integer types:
+// TypeWithSize - maps an integer to a int type.
+// Int32, UInt32, Int64, UInt64, TimeInMillis
+// - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GTEST_FLAG() - references a flag.
+// GTEST_DECLARE_*() - declares a flag.
+// GTEST_DEFINE_*() - defines a flag.
+// GetArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+// GetEnv() - gets the value of an environment variable.
+// BoolFromGTestEnv() - parses a bool environment variable.
+// Int32FromGTestEnv() - parses an Int32 environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream> // Used for GTEST_CHECK_
+
+#define GTEST_NAME "Google Test"
+#define GTEST_FLAG_PREFIX "gtest_"
+#define GTEST_FLAG_PREFIX_UPPER "GTEST_"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+#define GTEST_GCC_VER_ \
+ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+#define GTEST_OS_CYGWIN
+#elif __SYMBIAN32__
+#define GTEST_OS_SYMBIAN
+#elif defined _MSC_VER
+// TODO(kenton@google.com): GTEST_OS_WINDOWS is currently used to mean
+// both "The OS is Windows" and "The compiler is MSVC". These
+// meanings really should be separated in order to better support
+// Windows compilers other than MSVC.
+#define GTEST_OS_WINDOWS
+#elif defined __APPLE__
+#define GTEST_OS_MAC
+#elif defined __linux__
+#define GTEST_OS_LINUX
+#elif defined __MVS__
+#define GTEST_OS_ZOS
+#elif defined(__sun) && defined(__SVR4)
+#define GTEST_OS_SOLARIS
+#endif // _MSC_VER
+
+// Determines whether ::std::string and ::string are available.
+
+#ifndef GTEST_HAS_STD_STRING
+// The user didn't tell us whether ::std::string is available, so we
+// need to figure it out.
+
+#ifdef GTEST_OS_WINDOWS
+// Assumes that exceptions are enabled by default.
+#ifndef _HAS_EXCEPTIONS
+#define _HAS_EXCEPTIONS 1
+#endif // _HAS_EXCEPTIONS
+// GTEST_HAS_EXCEPTIONS is non-zero iff exceptions are enabled. It is
+// always defined, while _HAS_EXCEPTIONS is defined only on Windows.
+#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+// On Windows, we can use ::std::string if the compiler version is VS
+// 2005 or above, or if exceptions are enabled.
+#define GTEST_HAS_STD_STRING ((_MSC_VER >= 1400) || GTEST_HAS_EXCEPTIONS)
+#else // We are on Linux or Mac OS.
+#define GTEST_HAS_EXCEPTIONS 0
+#define GTEST_HAS_STD_STRING 1
+#endif // GTEST_OS_WINDOWS
+
+#endif // GTEST_HAS_STD_STRING
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+#define GTEST_HAS_GLOBAL_STRING 0
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
+// is available.
+
+#if defined(GTEST_OS_CYGWIN) || defined(GTEST_OS_SOLARIS)
+// At least some versions of cygwin don't support ::std::wstring.
+// Solaris' libc++ doesn't support it either.
+#define GTEST_HAS_STD_WSTRING 0
+#else
+#define GTEST_HAS_STD_WSTRING GTEST_HAS_STD_STRING
+#endif // defined(GTEST_OS_CYGWIN) || defined(GTEST_OS_SOLARIS)
+
+#endif // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+#define GTEST_HAS_GLOBAL_WSTRING GTEST_HAS_GLOBAL_STRING
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING || \
+ GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+#include <string> // NOLINT
+#endif // GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING ||
+ // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_STRING
+#include <sstream> // NOLINT
+#else
+#include <strstream> // NOLINT
+#endif // GTEST_HAS_STD_STRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+#ifdef _MSC_VER
+
+#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif // _CPPRTTI
+
+#elif defined(__GNUC__)
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+#if GTEST_GCC_VER_ >= 40302
+#ifdef __GXX_RTTI
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif // __GXX_RTTI
+#else
+// For gcc versions smaller than 4.3.2, we assume RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+#endif // GTEST_GCC_VER >= 40302
+
+#else
+
+// Unknown compiler - assume RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+
+#endif // _MSC_VER
+
+#endif // GTEST_HAS_RTTI
+
+// Determines whether <pthread.h> is available.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us, so we need to figure it out.
+
+#if defined(GTEST_OS_LINUX) || defined(GTEST_OS_MAC)
+#define GTEST_HAS_PTHREAD 1
+#else
+#define GTEST_HAS_PTHREAD 0
+#endif // GTEST_OS_LINUX || GTEST_OS_MAC
+
+#endif // GTEST_HAS_PTHREAD
+
+// Determines whether tr1/tuple is available. If you have tr1/tuple
+// on your platform, define GTEST_HAS_TR1_TUPLE=1 for both the Google
+// Test project and your tests. If you would like Google Test to detect
+// tr1/tuple on your platform automatically, please open an issue
+// ticket at http://code.google.com/p/googletest.
+#ifndef GTEST_HAS_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// GCC provides <tr1/tuple> since 4.0.0.
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+#define GTEST_HAS_TR1_TUPLE 1
+#else
+#define GTEST_HAS_TR1_TUPLE 0
+#endif // __GNUC__
+#endif // GTEST_HAS_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+#if defined(__GNUC__)
+// GCC implements tr1/tuple in the <tr1/tuple> header. This does not
+// conform to the TR1 spec, which requires the header to be <tuple>.
+#include <tr1/tuple>
+#else
+// If the compiler is not GCC, we assume the user is using a
+// spec-conforming TR1 implementation.
+#include <tuple>
+#endif // __GNUC__
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+#if defined(GTEST_OS_LINUX) && !defined(__ia64__)
+#define GTEST_HAS_CLONE 1
+#else
+#define GTEST_HAS_CLONE 0
+#endif // defined(GTEST_OS_LINUX) && !defined(__ia64__)
+
+#endif // GTEST_HAS_CLONE
+
+// Determines whether to support death tests.
+#if GTEST_HAS_STD_STRING && GTEST_HAS_CLONE
+#define GTEST_HAS_DEATH_TEST
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise. We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+#include <regex.h>
+#include <vector>
+#include <fcntl.h>
+#include <sys/mman.h>
+#endif // GTEST_HAS_STD_STRING && GTEST_HAS_CLONE
+
+// Determines whether to support value-parameterized tests.
+
+#if defined(__GNUC__) || (_MSC_VER >= 1400)
+// TODO(vladl@google.com): get the implementation rid of vector and list
+// to compile on MSVC 7.1.
+#define GTEST_HAS_PARAM_TEST
+#endif // defined(__GNUC__) || (_MSC_VER >= 1400)
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which gcc and VC
+// 8.0+ support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400)
+#define GTEST_HAS_TYPED_TEST
+#define GTEST_HAS_TYPED_TEST_P
+#endif // defined(__GNUC__) || (_MSC_VER >= 1400)
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled.
+#if defined(GTEST_HAS_PARAM_TEST) && GTEST_HAS_TR1_TUPLE
+#define GTEST_HAS_COMBINE
+#endif // defined(GTEST_HAS_PARAM_TEST) && GTEST_HAS_TR1_TUPLE
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#if defined(GTEST_OS_WINDOWS) || defined(GTEST_OS_CYGWIN) || \
+ defined(GTEST_OS_SYMBIAN)
+#define GTEST_WIDE_STRING_USES_UTF16_ 1
+#endif
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding. This leads to problems with code like:
+//
+// if (gate)
+// ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT
+#endif
+
+// Use this annotation at the end of a struct / class definition to
+// prevent the compiler from optimizing away instances that are never
+// used. This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor. Example:
+//
+// struct Foo {
+// Foo() { ... }
+// } GTEST_ATTRIBUTE_UNUSED_;
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+#define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+ type(const type &);\
+ void operator=(const type &)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro. The macro should be used on function declarations
+// following the argument list:
+//
+// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+#define GTEST_MUST_USE_RESULT_
+#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+class String;
+
+// std::strstream is deprecated. However, we have to use it on
+// Windows as std::stringstream won't compile on Windows when
+// exceptions are disabled. We use std::stringstream on other
+// platforms to avoid compiler warnings there.
+#if GTEST_HAS_STD_STRING
+typedef ::std::stringstream StrStream;
+#else
+typedef ::std::strstream StrStream;
+#endif // GTEST_HAS_STD_STRING
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+ explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+ ~scoped_ptr() { reset(); }
+
+ T& operator*() const { return *ptr_; }
+ T* operator->() const { return ptr_; }
+ T* get() const { return ptr_; }
+
+ T* release() {
+ T* const ptr = ptr_;
+ ptr_ = NULL;
+ return ptr;
+ }
+
+ void reset(T* p = NULL) {
+ if (p != ptr_) {
+ if (sizeof(T) > 0) { // Makes sure T is a complete type.
+ delete ptr_;
+ }
+ ptr_ = p;
+ }
+ }
+ private:
+ T* ptr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>. It uses the POSIX Enxtended
+// Regular Expression syntax.
+class RE {
+ public:
+ // Constructs an RE from a string.
+#if GTEST_HAS_STD_STRING
+ RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+ RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ RE(const char* regex) { Init(regex); } // NOLINT
+ ~RE();
+
+ // Returns the string representation of the regex.
+ const char* pattern() const { return pattern_; }
+
+ // FullMatch(str, re) returns true iff regular expression re matches
+ // the entire str.
+ // PartialMatch(str, re) returns true iff regular expression re
+ // matches a substring of str (including str itself).
+ //
+ // TODO(wan@google.com): make FullMatch() and PartialMatch() work
+ // when str contains NUL characters.
+#if GTEST_HAS_STD_STRING
+ static bool FullMatch(const ::std::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::std::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+ static bool FullMatch(const ::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ static bool FullMatch(const char* str, const RE& re);
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+
+ // We use a const char* instead of a string, as Google Test may be used
+ // where string is not available. We also do not use Google Test's own
+ // String type here, in order to simplify dependencies between the
+ // files.
+ const char* pattern_;
+ regex_t full_regex_; // For FullMatch().
+ regex_t partial_regex_; // For PartialMatch().
+ bool is_valid_;
+};
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines logging utilities:
+// GTEST_LOG_() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+ GTEST_INFO,
+ GTEST_WARNING,
+ GTEST_ERROR,
+ GTEST_FATAL
+};
+
+void GTestLog(GTestLogSeverity severity, const char* file,
+ int line, const char* msg);
+
+#define GTEST_LOG_(severity, msg)\
+ ::testing::internal::GTestLog(\
+ ::testing::internal::GTEST_##severity, __FILE__, __LINE__, \
+ (::testing::Message() << (msg)).GetString().c_str())
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// Defines the stderr capturer:
+// CaptureStderr - starts capturing stderr.
+// GetCapturedStderr - stops capturing stderr and returns the captured string.
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+extern ::std::vector<String> g_argvs;
+
+void CaptureStderr();
+// GTEST_HAS_DEATH_TEST implies we have ::std::string.
+::std::string GetCapturedStderr();
+const ::std::vector<String>& GetArgvs();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable). Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+ Mutex() {}
+ explicit Mutex(int /*unused*/) {}
+ void AssertHeld() const {}
+ enum { NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX = 0 };
+};
+
+// We cannot call it MutexLock directly as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+ ThreadLocal() : value_() {}
+ explicit ThreadLocal(const T& value) : value_(value) {}
+ T* pointer() { return &value_; }
+ const T* pointer() const { return &value_; }
+ const T& get() const { return value_; }
+ void set(const T& value) { value_ = value; }
+ private:
+ T value_;
+};
+
+// There's no portable way to detect the number of threads, so we just
+// return 0 to indicate that we cannot detect it.
+inline size_t GetThreadCount() { return 0; }
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+#define GTEST_IS_THREADSAFE 0
+
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler. The Nokia Symbian and the IBM XL C/C++ compiler try to
+// instantiate a copy constructor for objects passed through ellipsis
+// (...), failing for uncopyable objects. We define this to indicate
+// the fact.
+#define GTEST_ELLIPSIS_NEEDS_COPY_ 1
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template. These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#define GTEST_NEEDS_IS_POINTER_ 1
+
+#endif // defined(__SYMBIAN32__) || defined(__IBMCPP__)
+
+template <bool bool_value>
+struct bool_constant {
+ typedef bool_constant<bool_value> type;
+ static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+// Defines BiggestInt as the biggest signed integer type the compiler
+// supports.
+
+#ifdef GTEST_OS_WINDOWS
+typedef __int64 BiggestInt;
+#else
+typedef long long BiggestInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+// The maximum number a BiggestInt can represent. This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+ ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type. It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+// TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs. Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+ // unsigned int has size 4 in both gcc and MSVC.
+ //
+ // As base/basictypes.h doesn't compile on Windows, we cannot use
+ // uint32, uint64, and etc here.
+ typedef int Int;
+ typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+#ifdef GTEST_OS_WINDOWS
+ typedef __int64 Int;
+ typedef unsigned __int64 UInt;
+#else
+ typedef long long Int; // NOLINT
+ typedef unsigned long long UInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// A wrapper for getenv() that works on Linux, Windows, and Mac OS.
+inline const char* GetEnv(const char* name) {
+#ifdef _WIN32_WCE // We are on Windows CE.
+ // CE has no environment variables.
+ return NULL;
+#elif defined(GTEST_OS_WINDOWS) // We are on Windows proper.
+ // MSVC 8 deprecates getenv(), so we want to suppress warning 4996
+ // (deprecated function) there.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ return getenv(name);
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ return getenv(name);
+#endif
+}
+
+#ifdef _WIN32_WCE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void abort();
+#else
+inline void abort() { ::abort(); }
+#endif // _WIN32_WCE
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+// Synopsys:
+// GTEST_CHECK_(boolean_condition);
+// or
+// GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+// This checks the condition and if the condition is not satisfied
+// it prints message about the condition violation, including the
+// condition itself, plus additional message streamed into it, if any,
+// and then it aborts the program. It aborts the program irrespective of
+// whether it is built in the debug mode or not.
+class GTestCheckProvider {
+ public:
+ GTestCheckProvider(const char* condition, const char* file, int line) {
+ FormatFileLocation(file, line);
+ ::std::cerr << " ERROR: Condition " << condition << " failed. ";
+ }
+ ~GTestCheckProvider() {
+ ::std::cerr << ::std::endl;
+ abort();
+ }
+ void FormatFileLocation(const char* file, int line) {
+ if (file == NULL)
+ file = "unknown file";
+ if (line < 0) {
+ ::std::cerr << file << ":";
+ } else {
+#if _MSC_VER
+ ::std::cerr << file << "(" << line << "):";
+#else
+ ::std::cerr << file << ":" << line << ":";
+#endif
+ }
+ }
+ ::std::ostream& GetStream() { return ::std::cerr; }
+};
+#define GTEST_CHECK_(condition) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (condition) \
+ ; \
+ else \
+ ::testing::internal::GTestCheckProvider(\
+ #condition, __FILE__, __LINE__).GetStream()
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+ extern ::testing::internal::String GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+ ::testing::internal::String GTEST_FLAG(name) = (default_val)
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-string.h b/utils/unittest/googletest/include/gtest/internal/gtest-string.h
new file mode 100644
index 000000000000..178f14e1264b
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-string.h
@@ -0,0 +1,335 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test. They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by testing/base/internal/gtest-internal.h.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#include <string.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_GLOBAL_STRING || GTEST_HAS_STD_STRING
+#include <string>
+#endif // GTEST_HAS_GLOBAL_STRING || GTEST_HAS_STD_STRING
+
+namespace testing {
+namespace internal {
+
+// String - a UTF-8 string class.
+//
+// We cannot use std::string as Microsoft's STL implementation in
+// Visual C++ 7.1 has problems when exception is disabled. There is a
+// hack to work around this, but we've seen cases where the hack fails
+// to work.
+//
+// Also, String is different from std::string in that it can represent
+// both NULL and the empty string, while std::string cannot represent
+// NULL.
+//
+// NULL and the empty string are considered different. NULL is less
+// than anything (including the empty string) except itself.
+//
+// This class only provides minimum functionality necessary for
+// implementing Google Test. We do not intend to implement a full-fledged
+// string class here.
+//
+// Since the purpose of this class is to provide a substitute for
+// std::string on platforms where it cannot be used, we define a copy
+// constructor and assignment operators such that we don't need
+// conditional compilation in a lot of places.
+//
+// In order to make the representation efficient, the d'tor of String
+// is not virtual. Therefore DO NOT INHERIT FROM String.
+class String {
+ public:
+ // Static utility methods
+
+ // Returns the input if it's not NULL, otherwise returns "(null)".
+ // This function serves two purposes:
+ //
+ // 1. ShowCString(NULL) has type 'const char *', instead of the
+ // type of NULL (which is int).
+ //
+ // 2. In MSVC, streaming a null char pointer to StrStream generates
+ // an access violation, so we need to convert NULL to "(null)"
+ // before streaming it.
+ static inline const char* ShowCString(const char* c_str) {
+ return c_str ? c_str : "(null)";
+ }
+
+ // Returns the input enclosed in double quotes if it's not NULL;
+ // otherwise returns "(null)". For example, "\"Hello\"" is returned
+ // for input "Hello".
+ //
+ // This is useful for printing a C string in the syntax of a literal.
+ //
+ // Known issue: escape sequences are not handled yet.
+ static String ShowCStringQuoted(const char* c_str);
+
+ // Clones a 0-terminated C string, allocating memory using new. The
+ // caller is responsible for deleting the return value using
+ // delete[]. Returns the cloned string, or NULL if the input is
+ // NULL.
+ //
+ // This is different from strdup() in string.h, which allocates
+ // memory using malloc().
+ static const char* CloneCString(const char* c_str);
+
+#ifdef _WIN32_WCE
+ // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+ // able to pass strings to Win32 APIs on CE we need to convert them
+ // to 'Unicode', UTF-16.
+
+ // Creates a UTF-16 wide string from the given ANSI string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the wide string, or NULL if the
+ // input is NULL.
+ //
+ // The wide string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static LPCWSTR AnsiToUtf16(const char* c_str);
+
+ // Creates an ANSI string from the given wide string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the ANSI string, or NULL if the
+ // input is NULL.
+ //
+ // The returned string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+ // Compares two C strings. Returns true iff they have the same content.
+ //
+ // Unlike strcmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CStringEquals(const char* lhs, const char* rhs);
+
+ // Converts a wide C string to a String using the UTF-8 encoding.
+ // NULL will be converted to "(null)". If an error occurred during
+ // the conversion, "(failed to convert from wide string)" is
+ // returned.
+ static String ShowWideCString(const wchar_t* wide_c_str);
+
+ // Similar to ShowWideCString(), except that this function encloses
+ // the converted string in double quotes.
+ static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true iff they have the same
+ // content.
+ //
+ // Unlike wcscmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+ // Compares two C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike strcasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CaseInsensitiveCStringEquals(const char* lhs,
+ const char* rhs);
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+ static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs);
+
+ // Formats a list of arguments to a String, using the same format
+ // spec string as for printf.
+ //
+ // We do not use the StringPrintf class as it is not universally
+ // available.
+ //
+ // The result is limited to 4096 characters (including the tailing
+ // 0). If 4096 characters are not enough to format the input,
+ // "<buffer exceeded>" is returned.
+ static String Format(const char* format, ...);
+
+ // C'tors
+
+ // The default c'tor constructs a NULL string.
+ String() : c_str_(NULL) {}
+
+ // Constructs a String by cloning a 0-terminated C string.
+ String(const char* c_str) : c_str_(NULL) { // NOLINT
+ *this = c_str;
+ }
+
+ // Constructs a String by copying a given number of chars from a
+ // buffer. E.g. String("hello", 3) will create the string "hel".
+ String(const char* buffer, size_t len);
+
+ // The copy c'tor creates a new copy of the string. The two
+ // String objects do not share content.
+ String(const String& str) : c_str_(NULL) {
+ *this = str;
+ }
+
+ // D'tor. String is intended to be a final class, so the d'tor
+ // doesn't need to be virtual.
+ ~String() { delete[] c_str_; }
+
+ // Allows a String to be implicitly converted to an ::std::string or
+ // ::string, and vice versa. Converting a String containing a NULL
+ // pointer to ::std::string or ::string is undefined behavior.
+ // Converting a ::std::string or ::string containing an embedded NUL
+ // character to a String will result in the prefix up to the first
+ // NUL character.
+#if GTEST_HAS_STD_STRING
+ String(const ::std::string& str) : c_str_(NULL) { *this = str.c_str(); }
+
+ operator ::std::string() const { return ::std::string(c_str_); }
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+ String(const ::string& str) : c_str_(NULL) { *this = str.c_str(); }
+
+ operator ::string() const { return ::string(c_str_); }
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ // Returns true iff this is an empty string (i.e. "").
+ bool empty() const {
+ return (c_str_ != NULL) && (*c_str_ == '\0');
+ }
+
+ // Compares this with another String.
+ // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+ // if this is greater than rhs.
+ int Compare(const String& rhs) const;
+
+ // Returns true iff this String equals the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator==(const char* c_str) const {
+ return CStringEquals(c_str_, c_str);
+ }
+
+ // Returns true iff this String is less than the given C string. A NULL
+ // string is considered less than "".
+ bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
+
+ // Returns true iff this String doesn't equal the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator!=(const char* c_str) const {
+ return !CStringEquals(c_str_, c_str);
+ }
+
+ // Returns true iff this String ends with the given suffix. *Any*
+ // String is considered to end with a NULL or empty suffix.
+ bool EndsWith(const char* suffix) const;
+
+ // Returns true iff this String ends with the given suffix, not considering
+ // case. Any String is considered to end with a NULL or empty suffix.
+ bool EndsWithCaseInsensitive(const char* suffix) const;
+
+ // Returns the length of the encapsulated string, or -1 if the
+ // string is NULL.
+ int GetLength() const {
+ return c_str_ ? static_cast<int>(strlen(c_str_)) : -1;
+ }
+
+ // Gets the 0-terminated C string this String object represents.
+ // The String object still owns the string. Therefore the caller
+ // should NOT delete the return value.
+ const char* c_str() const { return c_str_; }
+
+ // Sets the 0-terminated C string this String object represents.
+ // The old string in this object is deleted, and this object will
+ // own a clone of the input string. This function copies only up to
+ // length bytes (plus a terminating null byte), or until the first
+ // null byte, whichever comes first.
+ //
+ // This function works even when the c_str parameter has the same
+ // value as that of the c_str_ field.
+ void Set(const char* c_str, size_t length);
+
+ // Assigns a C string to this object. Self-assignment works.
+ const String& operator=(const char* c_str);
+
+ // Assigns a String object to this object. Self-assignment works.
+ const String& operator=(const String &rhs) {
+ *this = rhs.c_str_;
+ return *this;
+ }
+
+ private:
+ const char* c_str_;
+};
+
+// Streams a String to an ostream.
+inline ::std::ostream& operator <<(::std::ostream& os, const String& str) {
+ // We call String::ShowCString() to convert NULL to "(null)".
+ // Otherwise we'll get an access violation on Windows.
+ return os << String::ShowCString(str.c_str());
+}
+
+// Gets the content of the StrStream's buffer as a String. Each '\0'
+// character in the buffer is replaced with "\\0".
+String StrStreamToString(StrStream* stream);
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-type-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-type-util.h
new file mode 100644
index 000000000000..815da4ba83cc
--- /dev/null
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-type-util.h
@@ -0,0 +1,3319 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework@googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-string.h>
+
+#if defined(GTEST_HAS_TYPED_TEST) || defined(GTEST_HAS_TYPED_TEST_P)
+
+#ifdef __GNUC__
+#include <cxxabi.h>
+#endif // __GNUC__
+
+#include <typeinfo>
+
+namespace testing {
+namespace internal {
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type. This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+ typedef bool type;
+};
+
+// GetTypeName<T>() returns a human-readable name of type T.
+template <typename T>
+String GetTypeName() {
+#if GTEST_HAS_RTTI
+
+ const char* const name = typeid(T).name();
+#ifdef __GNUC__
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+ char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status);
+ const String name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return name_str;
+#else
+ return name;
+#endif // __GNUC__
+
+#else
+ return "<type>";
+#endif // GTEST_HAS_RTTI
+}
+
+// A unique type used as the default value for the arguments of class
+// template Types. This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists. In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+ typedef T1 Head;
+ typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+ typedef T1 Head;
+ typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+ typedef T1 Head;
+ typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+ typedef T1 Head;
+ typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+ typedef T1 Head;
+ typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types6 {
+ typedef T1 Head;
+ typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types7 {
+ typedef T1 Head;
+ typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types8 {
+ typedef T1 Head;
+ typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+ typedef T1 Head;
+ typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+ typedef T1 Head;
+ typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types11 {
+ typedef T1 Head;
+ typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types12 {
+ typedef T1 Head;
+ typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types13 {
+ typedef T1 Head;
+ typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+ typedef T1 Head;
+ typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+ typedef T1 Head;
+ typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types16 {
+ typedef T1 Head;
+ typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types17 {
+ typedef T1 Head;
+ typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types18 {
+ typedef T1 Head;
+ typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+ typedef T1 Head;
+ typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+ typedef T1 Head;
+ typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types21 {
+ typedef T1 Head;
+ typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types22 {
+ typedef T1 Head;
+ typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types23 {
+ typedef T1 Head;
+ typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+ typedef T1 Head;
+ typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+ typedef T1 Head;
+ typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types26 {
+ typedef T1 Head;
+ typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types27 {
+ typedef T1 Head;
+ typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types28 {
+ typedef T1 Head;
+ typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+ typedef T1 Head;
+ typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+ typedef T1 Head;
+ typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types31 {
+ typedef T1 Head;
+ typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types32 {
+ typedef T1 Head;
+ typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types33 {
+ typedef T1 Head;
+ typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+ typedef T1 Head;
+ typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+ typedef T1 Head;
+ typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types36 {
+ typedef T1 Head;
+ typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types37 {
+ typedef T1 Head;
+ typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types38 {
+ typedef T1 Head;
+ typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+ typedef T1 Head;
+ typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+ typedef T1 Head;
+ typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types41 {
+ typedef T1 Head;
+ typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types42 {
+ typedef T1 Head;
+ typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types43 {
+ typedef T1 Head;
+ typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+ typedef T1 Head;
+ typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+ typedef T1 Head;
+ typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types46 {
+ typedef T1 Head;
+ typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types47 {
+ typedef T1 Head;
+ typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types48 {
+ typedef T1 Head;
+ typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+ typedef T1 Head;
+ typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+ typedef T1 Head;
+ typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+} // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length. Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+ typename T3 = internal::None, typename T4 = internal::None,
+ typename T5 = internal::None, typename T6 = internal::None,
+ typename T7 = internal::None, typename T8 = internal::None,
+ typename T9 = internal::None, typename T10 = internal::None,
+ typename T11 = internal::None, typename T12 = internal::None,
+ typename T13 = internal::None, typename T14 = internal::None,
+ typename T15 = internal::None, typename T16 = internal::None,
+ typename T17 = internal::None, typename T18 = internal::None,
+ typename T19 = internal::None, typename T20 = internal::None,
+ typename T21 = internal::None, typename T22 = internal::None,
+ typename T23 = internal::None, typename T24 = internal::None,
+ typename T25 = internal::None, typename T26 = internal::None,
+ typename T27 = internal::None, typename T28 = internal::None,
+ typename T29 = internal::None, typename T30 = internal::None,
+ typename T31 = internal::None, typename T32 = internal::None,
+ typename T33 = internal::None, typename T34 = internal::None,
+ typename T35 = internal::None, typename T36 = internal::None,
+ typename T37 = internal::None, typename T38 = internal::None,
+ typename T39 = internal::None, typename T40 = internal::None,
+ typename T41 = internal::None, typename T42 = internal::None,
+ typename T43 = internal::None, typename T44 = internal::None,
+ typename T45 = internal::None, typename T46 = internal::None,
+ typename T47 = internal::None, typename T48 = internal::None,
+ typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+ typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, internal::None, internal::None, internal::None> {
+ typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, internal::None, internal::None> {
+ typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, T49, internal::None> {
+ typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal {
+
+#define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+#define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates. This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists. In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN). Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates4 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates7 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates10 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates13 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates16 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates19 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates22 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates25 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates28 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates31 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates34 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates37 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates40 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates43 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates46 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates49 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length. Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+ GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+ GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+ GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+ GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+ GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+ GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+ GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+ GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+ GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+ GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+ GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+ GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+ GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+ GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+ GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+ GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+ GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+ GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+ GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+ GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+ GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+ GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+ GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+ GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+ typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, NoneT, NoneT, NoneT> {
+ typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, NoneT, NoneT> {
+ typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, T49, NoneT> {
+ typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList { typedef Types1<T> type; };
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> > {
+ typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/utils/userloc.pl b/utils/userloc.pl
new file mode 100755
index 000000000000..4da2f4029250
--- /dev/null
+++ b/utils/userloc.pl
@@ -0,0 +1,216 @@
+#!/usr/bin/perl -w
+#
+# Program: userloc.pl
+#
+# Synopsis: This program uses "cvs annotate" to get a summary of how many lines
+# of code the various developres are responsible for. It takes one
+# argument, the directory to process. If the argument is not specified
+# then the cwd is used. The directory must be an LLVM tree checked out
+# from cvs.
+#
+# Syntax: userloc.pl [-tag=tag|-html... <directory>...
+#
+# Options:
+# -tag=tag
+# Use "tag" to select the revision (as per cvs -r option)
+# -filedetails
+# Report details about lines of code in each file for each user
+# -html
+# Generate HTML output instead of text output
+# -topdir
+# Specify where the top llvm source directory is. Otherwise the
+# llvm-config tool is used to find it.
+# Directories:
+# The directories passed after the options should be relative paths to
+# directories of interest from the top of the llvm source tree, e.g. "lib"
+# or "include", etc.
+
+die "Usage userloc.pl [-tag=tag|-html] <directories>..."
+ if ($#ARGV < 0);
+
+my $tag = "";
+my $html = 0;
+my $debug = 0;
+my $filedetails = "";
+my $srcroot = "";
+while ( defined($ARGV[0]) && substr($ARGV[0],0,1) eq '-' )
+{
+ if ($ARGV[0] =~ /-tag=.*/) {
+ $tag = $ARGV[0];
+ $tag =~ s#-tag=(.*)#$1#;
+ } elsif ($ARGV[0] =~ /-filedetails/) {
+ $filedetails = 1;
+ } elsif ($ARGV[0] eq "-html") {
+ $html = 1;
+ } elsif ($ARGV[0] eq "-debug") {
+ $debug = 1;
+ } elsif ($ARGV[0] eq "-topdir") {
+ shift; $srcroot = $ARGV[0]; shift;
+ } else {
+ die "Invalid option: $ARGV[0]";
+ }
+ shift;
+}
+
+if (length($srcroot) == 0) {
+ chomp($srcroot = `llvm-config --src-root`);
+}
+if (! -d "$srcroot") {
+ die "Invalid source root: $srcroot\n";
+}
+chdir($srcroot);
+my $llvmdo = "$srcroot/utils/llvmdo -topdir '$srcroot'";
+my %Stats;
+my %FileStats;
+
+my $annotate = "cvs -z6 annotate -lf ";
+if (length($tag) > 0)
+{
+ $annotate = $annotate . " -r" . $tag;
+}
+
+sub GetCVSFiles
+{
+ my $d = $_[0];
+ my $files ="";
+ open FILELIST,
+ "$llvmdo -dirs \"$d\" -code-only echo |" || die "Can't get list of files with llvmdo";
+ while ( defined($line = <FILELIST>) ) {
+ chomp($file = $line);
+ print "File: $file\n" if ($debug);
+ $files = "$files $file";
+ }
+ return $files;
+}
+
+sub ScanDir
+{
+ my $Dir = $_[0];
+ my $files = GetCVSFiles($Dir);
+
+ open (DATA,"$annotate $files 2>&1 |")
+ || die "Can't read cvs annotation data";
+
+ my $curfile = "";
+ while ( defined($line = <DATA>) )
+ {
+ chomp($line);
+ if ($line =~ '^Annotations for.*') {
+ $curfile = $line;
+ $curfile =~ s#^Annotations for ([[:print:]]*)#$1#;
+ print "Scanning: $curfile\n" if ($debug);
+ } elsif ($line =~ /^[0-9.]*[ \t]*\([^)]*\):/) {
+ $uname = $line;
+ $uname =~ s#^[0-9.]*[ \t]*\(([a-zA-Z0-9_.-]*) [^)]*\):.*#$1#;
+ $Stats{$uname}++;
+ if ($filedetails) {
+ $FileStats{$uname} = {} unless exists $FileStats{$uname};
+ ${$FileStats{$uname}}{$curfile}++;
+ }
+ }
+ }
+ close DATA;
+}
+
+sub printStats
+{
+ my $dir = $_[0];
+ my $hash = $_[1];
+ my $user;
+ my $total = 0;
+
+ foreach $user (keys %Stats) { $total += $Stats{$user}; }
+
+ if ($html) {
+ print "<p>Total Source Lines: $total<br/></p>\n";
+ print "<table>";
+ print " <tr><th style=\"text-align:right\">LOC</th>\n";
+ print " <th style=\"text-align:right\">\%LOC</th>\n";
+ print " <th style=\"text-align:left\">User</th>\n";
+ print "</tr>\n";
+ }
+
+ foreach $user ( sort keys %Stats )
+ {
+ my $v = $Stats{$user};
+ if (defined($v))
+ {
+ if ($html) {
+ printf "<tr><td style=\"text-align:right\">%d</td><td style=\"text-align:right\">(%4.1f%%)</td><td style=\"text-align:left\">", $v, (100.0/$total)*$v;
+ if ($filedetails) {
+ print "<a href=\"#$user\">$user</a></td></tr>";
+ } else {
+ print $user,"</td></tr>";
+ }
+ } else {
+ printf "%8d (%4.1f%%) %s\n", $v, (100.0/$total)*$v, $user;
+ }
+ }
+ }
+ print "</table>\n" if ($html);
+
+ if ($filedetails) {
+ foreach $user (sort keys %FileStats) {
+ my $total = 0;
+ foreach $file (sort keys %{$FileStats{$user}}) {
+ $total += ${$FileStats{$user}}{$file}
+ }
+ if ($html) {
+ print "<table><tr><th style=\"text-align:left\" colspan=\"3\"><a name=\"$user\">$user</a></th></tr>\n";
+ } else {
+ print $user,":\n";
+ }
+ foreach $file (sort keys %{$FileStats{$user}}) {
+ my $v = ${$FileStats{$user}}{$file};
+ if ($html) {
+ printf "<tr><td style=\"text-align:right\">&nbsp;&nbsp;%d</td><td
+ style=\"text-align:right\">&nbsp;%4.1f%%</td><td
+ style=\"text-align:left\">%s</td></tr>",$v, (100.0/$total)*$v,$file;
+ } else {
+ printf "%8d (%4.1f%%) %s\n", $v, (100.0/$total)*$v, $file;
+ }
+ }
+ if ($html) { print "</table>\n"; }
+ }
+ }
+}
+
+
+if ($html)
+{
+print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
+print "<html>\n<head>\n";
+print " <title>LLVM LOC Based On CVS Annotation</title>\n";
+print " <link rel=\"stylesheet\" href=\"llvm.css\" type=\"text/css\"/>\n";
+print "</head>\n";
+print "<body><div class=\"doc_title\">LLVM LOC Based On CVS Annotation</div>\n";
+print "<p>This document shows the total lines of code per user in each\n";
+print "LLVM directory. Lines of code are attributed by the user that last\n";
+print "committed the line. This does not necessarily reflect authorship.</p>\n";
+}
+
+my @DIRS;
+if ($#ARGV > 0) {
+ @DIRS = @ARGV;
+} else {
+ push @DIRS, 'include';
+ push @DIRS, 'lib';
+ push @DIRS, 'tools';
+ push @DIRS, 'runtime';
+ push @DIRS, 'docs';
+ push @DIRS, 'test';
+ push @DIRS, 'utils';
+ push @DIRS, 'examples';
+ push @DIRS, 'projects/Stacker';
+ push @DIRS, 'projects/sample';
+ push @DIRS, 'autoconf';
+}
+
+for $Index ( 0 .. $#DIRS) {
+ print "Scanning Dir: $DIRS[$Index]\n" if ($debug);
+ ScanDir($DIRS[$Index]);
+}
+
+printStats;
+
+print "</body></html>\n" if ($html) ;
diff --git a/utils/vim/README b/utils/vim/README
new file mode 100644
index 000000000000..bca25bfe6127
--- /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
+ 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
+
+
+If you prefer, instead of making copies you can make symlinks from
+~/.vim/syntax/... to the syntax files in your LLVM source tree. Apparently
+this did not work with older versions of vim however, so if this doesn't
+work you may need to make actual copies of the files.
+
+Another option, if you do not already have a ~/.vim/syntax directory, is
+to symlink ~/.vim/syntax itself to llvm/utils/vim .
+
+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 000000000000..201d8ddddbeb
--- /dev/null
+++ b/utils/vim/llvm.vim
@@ -0,0 +1,104 @@
+" 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
+
+" Types.
+" Types also include struct, array, vector, etc. but these don't
+" benefit as much from having dedicated highlighting rules.
+syn keyword llvmType void float double
+syn keyword llvmType x86_fp80 fp128 ppc_fp128
+syn keyword llvmType type label opaque
+syn match llvmType /\<i\d\+\>/
+
+" Instructions.
+" The true and false tokens can be used for comparison opcodes, but it's
+" much more common for these tokens to be used for boolean constants.
+syn keyword llvmStatement add sub mul sdiv udiv fdiv srem urem frem
+syn keyword llvmStatement and or xor
+syn keyword llvmStatement icmp fcmp
+syn keyword llvmStatement eq ne ugt uge ult ule sgt sge slt sle
+syn keyword llvmStatement oeq ogt oge olt ole one ord ueq ugt uge
+syn keyword llvmStatement ult ule une uno
+syn keyword llvmStatement phi call select shl lshr ashr va_arg
+syn keyword llvmStatement trunc zext sext
+syn keyword llvmStatement fptrunc fpext fptoui fptosi uitofp sitofp
+syn keyword llvmStatement ptrtoint inttoptr bitcast
+syn keyword llvmStatement ret br switch invoke unwind unreachable
+syn keyword llvmStatement malloc alloca free load store getelementptr
+syn keyword llvmStatement extractelement insertelement shufflevector
+syn keyword llvmStatement extractvalue insertvalue
+
+" Keywords.
+syn keyword llvmKeyword define declare global constant
+syn keyword llvmKeyword internal external
+syn keyword llvmKeyword linkonce linkonce_odr weak weak_odr appending
+syn keyword llvmKeyword common extern_weak
+syn keyword llvmKeyword thread_local dllimport dllexport
+syn keyword llvmKeyword hidden protected default
+syn keyword llvmKeyword except deplibs
+syn keyword llvmKeyword volatile fastcc coldcc cc ccc
+syn keyword llvmKeyword x86_stdcallcc x86_fastcallcc
+syn keyword llvmKeyword signext zeroext inreg sret nounwind noreturn
+syn keyword llvmKeyword nocapture byval nest readnone readonly
+syn keyword llvmKeyword noinline alwaysinline optsize ssp sspreq
+syn keyword llvmKeyword module asm align tail to
+syn keyword llvmKeyword addrspace section alias sideeffect c gc
+syn keyword llvmKeyword target datalayout triple
+
+" Obsolete keywords.
+syn keyword llvmError uninitialized implementation
+syn keyword llvmError getresult big little endian begin end
+
+" Misc syntax.
+syn match llvmIgnore /[%@]\d\+\>/
+syn match llvmNumber /-\?\<\d\+\>/
+syn match llvmFloat /-\?\<\d\+\.\d*\(e[+-]\d\+\)\?\>/
+syn match llvmFloat /\<0x\x\+\>/
+syn keyword llvmBoolean true false
+syn keyword llvmConstant zeroinitializer undef null
+syn match llvmComment /;.*$/
+syn region llvmString start=/"/ skip=/\\"/ end=/"/
+syn match llvmLabel /[\-a-zA-Z\$._0-9]*:/
+
+" Syntax-highlight dejagnu test commands.
+syn match llvmSpecialComment /;\s*RUN:.*$/
+syn match llvmSpecialComment /;\s*PR\d*\s*$/
+syn match llvmSpecialComment /;\s*END\.\s*$/
+syn match llvmSpecialComment /;\s*XFAIL:.*$/
+syn match llvmSpecialComment /;\s*XTARGET:.*$/
+
+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
+ HiLink llvmKeyword Keyword
+ HiLink llvmBoolean Boolean
+ HiLink llvmFloat Float
+ HiLink llvmIgnore Ignore
+ HiLink llvmConstant Constant
+ HiLink llvmSpecialComment SpecialComment
+ HiLink llvmError Error
+
+ 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 000000000000..ad358728e5f8
--- /dev/null
+++ b/utils/vim/tablegen.vim
@@ -0,0 +1,54 @@
+" 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
+
+" May be changed if you have a really slow machine
+syntax sync minlines=100
+
+syn case match
+
+syn keyword tgKeyword def let in code dag field include defm
+syn keyword tgType class int string list bit bits multiclass
+
+syn match tgNumber /\<\d\+\>/
+syn match tgNumber /\<\d\+\.\d*\>/
+syn match tgNumber /\<0b[01]\+\>/
+syn match tgNumber /\<0x[0-9a-fA-F]\+\>/
+syn region tgString start=/"/ skip=/\\"/ end=/"/ oneline
+
+syn region tgCode start=/\[{/ end=/}\]/
+
+syn keyword tgTodo contained TODO FIXME
+syn match tgComment /\/\/.*$/ contains=tgTodo
+" Handle correctly imbricated comment
+syn region tgComment2 matchgroup=tgComment2 start=+/\*+ end=+\*/+ contains=tgTodo,tgComment2
+
+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 tgComment2 Comment
+ HiLink tgString String
+ " May find a better Hilight group...
+ HiLink tgCode Special
+ HiLink tgTodo Todo
+
+ delcommand HiLink
+endif
+
+let b:current_syntax = "tablegen"
diff --git a/utils/vim/vimrc b/utils/vim/vimrc
new file mode 100644
index 000000000000..7b1fd872b274
--- /dev/null
+++ b/utils/vim/vimrc
@@ -0,0 +1,72 @@
+" LLVM coding guidelines conformance for VIM
+"
+" Maintainer: The LLVM Team, http://llvm.org
+" WARNING: Read before you source in all these commands and macros! Some
+" of them may change VIM behavior that you depend on.
+"
+" You can run VIM with these settings without changing your current setup with:
+" $ vim -u /path/to/llvm/utils/vim/vimrc
+
+" It's VIM, not VI
+set nocompatible
+
+" Wrap text at 80 cols
+set textwidth=80
+
+" A tab produces a 2-space indentation
+set softtabstop=2
+set shiftwidth=2
+set expandtab
+
+" Highlight trailing whitespace
+highlight WhitespaceEOL ctermbg=DarkYellow guibg=DarkYellow
+match WhitespaceEOL /\s\+$/
+
+" Enable filetype detection
+filetype on
+
+" Optional
+" C/C++ programming helpers
+augroup csrc
+ au!
+ autocmd FileType * set nocindent smartindent
+ autocmd FileType c,cpp set cindent
+augroup END
+" Set a few indentation parameters. See the VIM help for cinoptions-values for
+" details. These aren't absolute rules; they're just an approximation of
+" common style in LLVM source.
+set cinoptions=:0,g0,(0,Ws
+" Add and delete spaces in increments of `shiftwidth' for tabs
+set smarttab
+
+" Highlight syntax in programming languages
+syntax 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
+command! DeleteTrailingWs :%s/\s\+$//
+
+" Convert all tab characters to two spaces
+command! Untab :%s/\t/ /g
+
+" Enable syntax highlighting for LLVM files. To use, copy
+" utils/vim/llvm.vim to ~/.vim/syntax .
+augroup filetype
+ au! BufRead,BufNewFile *.ll set filetype=llvm
+augroup END
+
+" Enable syntax highlighting for tablegen files. To use, copy
+" utils/vim/tablegen.vim to ~/.vim/syntax .
+augroup filetype
+ au! BufRead,BufNewFile *.td set filetype=tablegen
+augroup END
diff --git a/utils/webNLT.pl b/utils/webNLT.pl
new file mode 100755
index 000000000000..fb29fd292e2d
--- /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();