aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rwxr-xr-xutils/CollectDebugInfoUsingLLDB.py182
-rwxr-xr-xutils/CompareDebugInfo.py182
-rw-r--r--utils/FileCheck/CMakeLists.txt2
-rw-r--r--utils/FileCheck/FileCheck.cpp65
-rw-r--r--utils/FileCheck/Makefile6
-rw-r--r--utils/FileUpdate/CMakeLists.txt2
-rw-r--r--utils/FileUpdate/FileUpdate.cpp20
-rw-r--r--utils/FileUpdate/Makefile6
-rwxr-xr-xutils/GenLibDeps.pl2
-rwxr-xr-xutils/GetRepositoryPath27
-rwxr-xr-xutils/GetSourceVersion20
-rw-r--r--utils/KillTheDoctor/CMakeLists.txt5
-rw-r--r--utils/KillTheDoctor/KillTheDoctor.cpp596
-rw-r--r--utils/Makefile2
-rw-r--r--utils/OldenDataRecover.pl37
-rw-r--r--utils/PerfectShuffle/PerfectShuffle.cpp3
-rw-r--r--utils/TableGen/ARMDecoderEmitter.cpp313
-rw-r--r--utils/TableGen/ARMDecoderEmitter.h2
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp2362
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp122
-rw-r--r--utils/TableGen/AsmWriterInst.cpp112
-rw-r--r--utils/TableGen/AsmWriterInst.h36
-rw-r--r--utils/TableGen/CMakeLists.txt12
-rw-r--r--utils/TableGen/CallingConvEmitter.cpp12
-rw-r--r--utils/TableGen/ClangASTNodesEmitter.h2
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp94
-rw-r--r--utils/TableGen/ClangAttrEmitter.h13
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp26
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp229
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.h31
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp253
-rw-r--r--utils/TableGen/CodeEmitterGen.h8
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp796
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h208
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp519
-rw-r--r--utils/TableGen/CodeGenInstruction.h231
-rw-r--r--utils/TableGen/CodeGenRegisters.h6
-rw-r--r--utils/TableGen/CodeGenTarget.cpp114
-rw-r--r--utils/TableGen/CodeGenTarget.h17
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp42
-rw-r--r--utils/TableGen/DAGISelMatcher.h368
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp38
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp273
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp18
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp7
-rw-r--r--utils/TableGen/EDEmitter.cpp288
-rw-r--r--utils/TableGen/FastISelEmitter.cpp70
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp1372
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.h56
-rw-r--r--utils/TableGen/InstrEnumEmitter.cpp2
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp33
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp204
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.cpp335
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.h4
-rw-r--r--utils/TableGen/Makefile2
-rw-r--r--utils/TableGen/NeonEmitter.cpp1059
-rw-r--r--utils/TableGen/NeonEmitter.h78
-rw-r--r--utils/TableGen/Record.cpp200
-rw-r--r--utils/TableGen/Record.h42
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp24
-rw-r--r--utils/TableGen/StringMatcher.cpp149
-rw-r--r--utils/TableGen/StringMatcher.h54
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp106
-rw-r--r--utils/TableGen/SubtargetEmitter.h7
-rw-r--r--utils/TableGen/TGLexer.cpp68
-rw-r--r--utils/TableGen/TGLexer.h15
-rw-r--r--utils/TableGen/TGParser.cpp268
-rw-r--r--utils/TableGen/TGParser.h12
-rw-r--r--utils/TableGen/TableGen.cpp49
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp16
-rw-r--r--utils/TableGen/X86ModRMFilters.h2
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp33
-rw-r--r--utils/TableGen/X86RecognizableInstr.h5
-rw-r--r--utils/Target/ARM/analyze-match-table.py61
-rwxr-xr-xutils/buildit/build_llvm14
-rw-r--r--utils/emacs/llvm-mode.el17
-rw-r--r--utils/emacs/tablegen-mode.el14
-rwxr-xr-xutils/findmisopt4
-rwxr-xr-xutils/findoptdiff6
-rw-r--r--utils/fpcmp/Makefile6
-rw-r--r--utils/kate/README12
-rw-r--r--utils/kate/llvm.xml255
-rw-r--r--utils/lit/TODO10
-rw-r--r--utils/lit/lit/LitConfig.py19
-rw-r--r--utils/lit/lit/LitFormats.py1
-rw-r--r--utils/lit/lit/TestFormats.py23
-rw-r--r--utils/lit/lit/TestRunner.py21
-rw-r--r--utils/lit/lit/TestingConfig.py2
-rw-r--r--utils/lit/lit/Util.py18
-rw-r--r--utils/lit/lit/__init__.py6
-rwxr-xr-xutils/lit/lit/main.py (renamed from utils/lit/lit/lit.py)0
-rw-r--r--utils/lit/setup.py23
-rw-r--r--utils/llvm-lit/CMakeLists.txt12
-rw-r--r--utils/llvm-lit/llvm-lit.in6
-rwxr-xr-xutils/llvm-native-gcc4
-rwxr-xr-xutils/llvm-native-gxx4
-rw-r--r--utils/not/CMakeLists.txt2
-rw-r--r--utils/not/Makefile6
-rw-r--r--utils/not/not.cpp16
-rwxr-xr-xutils/profile.pl4
-rwxr-xr-xutils/release/test-release.sh398
-rwxr-xr-xutils/test_debuginfo.pl61
-rw-r--r--utils/unittest/CMakeLists.txt41
-rw-r--r--utils/unittest/UnitTestMain/TestMain.cpp27
-rw-r--r--utils/unittest/googletest/gtest.cc35
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-port.h3
-rw-r--r--utils/valgrind/x86_64-pc-linux-gnu.supp8
-rw-r--r--utils/vim/llvm.vim3
-rw-r--r--utils/vim/vimrc9
109 files changed, 9298 insertions, 3827 deletions
diff --git a/utils/CollectDebugInfoUsingLLDB.py b/utils/CollectDebugInfoUsingLLDB.py
new file mode 100755
index 000000000000..4dbd19afa62b
--- /dev/null
+++ b/utils/CollectDebugInfoUsingLLDB.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+#
+# Be sure to add the python path that points to the LLDB shared library.
+# On MacOSX csh, tcsh:
+# setenv PYTHONPATH /Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python
+# On MacOSX sh, bash:
+# export PYTHONPATH=/Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python
+#
+# This script collect debugging information using LLDB. This script is
+# used by TEST=dbg in llvm testsuite to measure quality of debug info in
+# optimized builds.
+#
+# Usage:
+# export PYTHONPATH=...
+# ./CollectDebugInfUsingLLDB.py program bp_file out_file
+# program - Executable program with debug info.
+# bp_file - Simple text file listing breakpoints.
+# <absolute file name> <line number>
+# out_file - Output file where the debug info will be emitted.
+#----------------------------------------------------------------------
+
+import lldb
+import os
+import sys
+import time
+
+# AlreadyPrintedValues - A place to keep track of recursive values.
+AlreadyPrintedValues = {}
+
+# ISAlreadyPrinted - Return true if value is already printed.
+def IsAlreadyPrinted(value_name):
+ if AlreadyPrintedValues.get(value_name) is None:
+ AlreadyPrintedValues[value_name] = 1
+ return False
+ return True
+
+
+# print_var_value - Print a variable's value.
+def print_var_value (v, file, frame):
+ if v.IsValid() == False:
+ return
+ if IsAlreadyPrinted(v.GetName()):
+ return
+ total_children = v.GetNumChildren()
+ if total_children > 0:
+ c = 0
+ while (c < total_children) :
+ child = v.GetChildAtIndex(c)
+ if child is None:
+ file.write("None")
+ else:
+ if (child.GetName()) is None:
+ file.write("None")
+ else:
+ file.write(child.GetName())
+ file.write('=')
+ print_var_value(child, file, frame)
+ file.write(',')
+ c = c + 1
+ else:
+ if v.GetValue(frame) is None:
+ file.write("None")
+ else:
+ file.write(v.GetValue(frame))
+
+# print_vars - Print variable values in output file.
+def print_vars (tag, vars, fname, line, file, frame, target, thread):
+ # disable this thread.
+ count = thread.GetStopReasonDataCount()
+ bid = 0
+ tid = 0
+ for i in range(count):
+ id = thread.GetStopReasonDataAtIndex(i)
+ bp = target.FindBreakpointByID(id)
+ if bp.IsValid():
+ if bp.IsEnabled() == True:
+ bid = bp.GetID()
+ tid = bp.GetThreadID()
+ bp.SetEnabled(False)
+ else:
+ bp_loc = bp.FindLocationByID(thread.GetStopReasonDataAtIndex(i+1))
+ if bp_loc.IsValid():
+ bid = bp_loc.GetBreakPoint().GetID()
+ tid = bp_loc.ThreadGetID()
+ bp_loc.SetEnabled(False);
+
+ for i in range(vars.GetSize()):
+ v = vars.GetValueAtIndex(i)
+ if v.GetName() is not None:
+ file.write(tag)
+ file.write(fname)
+ file.write(':')
+ file.write(str(line))
+ file.write(' ')
+ file.write(str(tid))
+ file.write(':')
+ file.write(str(bid))
+ file.write(' ')
+ file.write(v.GetName())
+ file.write(' ')
+ AlreadyPrintedValues.clear()
+ print_var_value (v, file, frame)
+ file.write('\n')
+
+# set_breakpoints - set breakpoints as listed in input file.
+def set_breakpoints (target, breakpoint_filename, file):
+ f = open(breakpoint_filename, "r")
+ lines = f.readlines()
+ for l in range(len(lines)):
+ c = lines[l].split()
+ # print "setting break point - ", c
+ bp = target.BreakpointCreateByLocation (str(c[0]), int(c[1]))
+ file.write("#Breakpoint ")
+ file.write(str(c[0]))
+ file.write(':')
+ file.write(str(c[1]))
+ file.write(' ')
+ file.write(str(bp.GetThreadID()))
+ file.write(':')
+ file.write(str(bp.GetID()))
+ file.write('\n')
+ f.close()
+
+# stopeed_at_breakpoint - Return True if process is stopeed at a
+# breakpoint.
+def stopped_at_breakpoint (process):
+ if process.IsValid():
+ state = process.GetState()
+ if state == lldb.eStateStopped:
+ thread = process.GetThreadAtIndex(0)
+ if thread.IsValid():
+ if thread.GetStopReason() == lldb.eStopReasonBreakpoint:
+ return True
+ return False
+
+# Create a new debugger instance
+debugger = lldb.SBDebugger.Create()
+
+# When we step or continue, don't return from the function until the process
+# stops. We do this by setting the async mode to false.
+debugger.SetAsync (False)
+
+# Create a target from a file and arch
+##print "Creating a target for '%s'" % sys.argv[1]
+
+target = debugger.CreateTargetWithFileAndArch (sys.argv[1], lldb.LLDB_ARCH_DEFAULT)
+
+if target.IsValid():
+ #print "target is valid"
+ file=open(str(sys.argv[3]), 'w')
+ set_breakpoints (target, sys.argv[2], file)
+
+ # Launch the process. Since we specified synchronous mode, we won't return
+ # from this function until we hit the breakpoint at main
+ sberror = lldb.SBError()
+ process = target.Launch (None, None, os.ctermid(), os.ctermid(), os.ctermid(), None, 0, False, sberror)
+ # Make sure the launch went ok
+ while stopped_at_breakpoint(process):
+ thread = process.GetThreadAtIndex (0)
+ frame = thread.GetFrameAtIndex (0)
+ if frame.IsValid():
+ # #Print some simple frame info
+ ##print frame
+ #print "frame is valid"
+ function = frame.GetFunction()
+ if function.IsValid():
+ fname = function.GetMangledName()
+ if fname is None:
+ fname = function.GetName()
+ #print "function : ",fname
+ line = frame.GetLineEntry().GetLine()
+ vars = frame.GetVariables(1,0,0,0)
+ print_vars ("#Argument ", vars, fname, line, file, frame, target, thread)
+ # vars = frame.GetVariables(0,1,0,0)
+ # print_vars ("#Variables ", vars, fname, line, file, frame, target, thread)
+
+ process.Continue()
+ file.close()
+
+lldb.SBDebugger.Terminate()
diff --git a/utils/CompareDebugInfo.py b/utils/CompareDebugInfo.py
new file mode 100755
index 000000000000..2cd647e43a85
--- /dev/null
+++ b/utils/CompareDebugInfo.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+
+import os
+import sys
+
+DBG_OUTPUT_FILE="Output/" + sys.argv[1] + ".dbg.out"
+OPT_DBG_OUTPUT_FILE="Output/" + sys.argv[1] + ".dbg.opt.out"
+LOG_FILE="Output/" + sys.argv[1] + ".log"
+NATIVE_DBG_OUTPUT_FILE="Output/" + sys.argv[1] + ".native.dbg.out"
+NATIVE_OPT_DBG_OUTPUT_FILE="Output/" + sys.argv[1] + ".native.dbg.opt.out"
+NATIVE_LOG_FILE="Output/" + sys.argv[1] + ".native.log"
+REPORT_FILE="Output/" + sys.argv[1] + ".dbg.report.html"
+
+class BreakPoint:
+ def __init__(self, bp_name):
+ self.name = bp_name
+ self.values = {}
+ self.missing_args = []
+ self.matching_args = []
+ self.notmatching_args = []
+ self.missing_bp = False
+
+ def setMissing(self):
+ self.missing_bp = True
+
+ def getArgCount(self):
+ return len(self.values)
+
+ def getMissingArgCount(self):
+ if self.missing_bp == True:
+ return len(self.values)
+ return len(self.missing_args)
+
+ def getMatchingArgCount(self):
+ if self.missing_bp == True:
+ return 0
+ return len(self.matching_args)
+
+ def getNotMatchingArgCount(self):
+ if self.missing_bp == True:
+ return 0
+ return len(self.notmatching_args)
+
+ def recordArgument(self, arg_name, value):
+ self.values[arg_name] = value
+
+ def __repr__(self):
+ print self.name
+ items = self.values.items()
+ for i in range(len(items)):
+ print items[i][0]," = ",items[i][1]
+ return ''
+
+ def compare_args(self, other, file):
+ myitems = self.values.items()
+ otheritems = other.values.items()
+ match = False
+ for i in range(len(myitems)):
+ if i >= len(otheritems):
+ match = True
+ self.missing_args.append(myitems[i][0])
+ elif cmp(myitems[i][1], otheritems[i][1]):
+ match = True
+ self.notmatching_args.append(myitems[i][0])
+ else:
+ self.matching_args.append(myitems[i][0])
+
+ self.print_list(self.matching_args, " Matching arguments ", file)
+ self.print_list(self.notmatching_args, " Not Matching arguments ", file)
+ self.print_list(self.missing_args, " Missing arguments ", file)
+ return match
+
+ def print_list(self, items, txt, pfile):
+ if len(items) == 0:
+ return
+ pfile.write(self.name)
+ pfile.write(txt)
+ for e in items:
+ pfile.write(e)
+ pfile.write(' ')
+ pfile.write('\n')
+
+def read_input(filename, dict):
+ f = open(filename, "r")
+ lines = f.readlines()
+ for l in range(len(lines)):
+ c = lines[l].split()
+ if c[0] == "#Breakpoint":
+ bp = dict.get(c[2])
+ if bp is None:
+ bp = BreakPoint(c[1])
+ dict[c[2]] = bp
+ if c[0] == "#Argument":
+ bp = dict.get(c[2])
+ if bp is None:
+ bp = BreakPoint(c[1])
+ dict[c[2]] = bp
+ bp.recordArgument(c[3], c[4])
+ return
+
+f1_breakpoints = {}
+read_input(DBG_OUTPUT_FILE, f1_breakpoints)
+f1_items = f1_breakpoints.items()
+
+f2_breakpoints = {}
+read_input(OPT_DBG_OUTPUT_FILE, f2_breakpoints)
+f2_items = f2_breakpoints.items()
+
+f = open(LOG_FILE, "w")
+f.write("Log output\n")
+for f2bp in range(len(f2_items)):
+ id = f2_items[f2bp][0]
+ bp = f2_items[f2bp][1]
+ bp1 = f1_breakpoints.get(id)
+ if bp1 is None:
+ bp.setMissing()
+ else:
+ bp1.compare_args(bp,f)
+f.close()
+
+nf1_breakpoints = {}
+read_input(NATIVE_DBG_OUTPUT_FILE, nf1_breakpoints)
+nf1_items = nf1_breakpoints.items()
+
+nf2_breakpoints = {}
+read_input(NATIVE_OPT_DBG_OUTPUT_FILE, nf2_breakpoints)
+nf2_items = nf2_breakpoints.items()
+
+nfl = open(NATIVE_LOG_FILE, "w")
+for nf2bp in range(len(nf2_items)):
+ id = nf2_items[nf2bp][0]
+ bp = nf2_items[nf2bp][1]
+ bp1 = nf1_breakpoints.get(id)
+ if bp1 is None:
+ bp.setMissing()
+ else:
+ bp1.compare_args(bp,nfl)
+nfl.close()
+
+f1_arg_count = 0
+f1_matching_arg_count = 0
+f1_notmatching_arg_count = 0
+f1_missing_arg_count = 0
+for idx in range(len(f1_items)):
+ bp = f1_items[idx][1]
+ f1_arg_count = f1_arg_count + bp.getArgCount()
+ f1_matching_arg_count = f1_matching_arg_count + bp.getMatchingArgCount()
+ f1_notmatching_arg_count = f1_notmatching_arg_count + bp.getNotMatchingArgCount()
+ f1_missing_arg_count = f1_missing_arg_count + bp.getMissingArgCount()
+
+nf1_arg_count = 0
+nf1_matching_arg_count = 0
+nf1_notmatching_arg_count = 0
+nf1_missing_arg_count = 0
+for idx in range(len(nf1_items)):
+ bp = nf1_items[idx][1]
+ nf1_arg_count = nf1_arg_count + bp.getArgCount()
+ nf1_matching_arg_count = nf1_matching_arg_count + bp.getMatchingArgCount()
+ nf1_notmatching_arg_count = nf1_notmatching_arg_count + bp.getNotMatchingArgCount()
+ nf1_missing_arg_count = nf1_missing_arg_count + bp.getMissingArgCount()
+
+rf = open(REPORT_FILE, "w")
+rf.write("<tr><td>")
+rf.write(str(sys.argv[1]))
+rf.write("</td><td>|</td><td>")
+rf.write(str(nf1_arg_count))
+rf.write("</td><td><b>")
+rf.write(str(nf1_matching_arg_count))
+rf.write("</b></td><td>")
+rf.write(str(nf1_notmatching_arg_count))
+rf.write("</td><td>")
+rf.write(str(nf1_missing_arg_count))
+rf.write("</td><td>|</td><td>")
+rf.write(str(f1_arg_count))
+rf.write("</td><td><b>")
+rf.write(str(f1_matching_arg_count))
+rf.write("</b></td><td>")
+rf.write(str(f1_notmatching_arg_count))
+rf.write("</td><td>")
+rf.write(str(f1_missing_arg_count))
+rf.write("\n")
+rf.close()
diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt
index 8fee03fb57b0..54db453e70e8 100644
--- a/utils/FileCheck/CMakeLists.txt
+++ b/utils/FileCheck/CMakeLists.txt
@@ -2,7 +2,7 @@ add_executable(FileCheck
FileCheck.cpp
)
-target_link_libraries(FileCheck LLVMSupport LLVMSystem)
+target_link_libraries(FileCheck LLVMSupport)
if( MINGW )
target_link_libraries(FileCheck imagehlp psapi)
endif( MINGW )
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index cd76d4404308..5d4cb0c0c5f0 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -16,13 +16,15 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Signals.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include <algorithm>
@@ -50,6 +52,10 @@ NoCanonicalizeWhiteSpace("strict-whitespace",
class Pattern {
SMLoc PatternLoc;
+ /// MatchEOF - When set, this pattern only matches the end of file. This is
+ /// used for trailing CHECK-NOTs.
+ bool MatchEOF;
+
/// FixedStr - If non-empty, this pattern is a fixed string match with the
/// specified fixed string.
StringRef FixedStr;
@@ -71,7 +77,7 @@ class Pattern {
public:
- Pattern() { }
+ Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { }
bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
@@ -271,6 +277,12 @@ bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen,
/// there is a match, the size of the matched string is returned in MatchLen.
size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const {
+ // If this is the EOF pattern, match it immediately.
+ if (MatchEOF) {
+ MatchLen = 0;
+ return Buffer.size();
+ }
+
// If this is a fixed string pattern, just match it now.
if (!FixedStr.empty()) {
MatchLen = FixedStr.size();
@@ -446,6 +458,11 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd();
Ptr != End; ++Ptr) {
+ // Eliminate trailing dosish \r.
+ if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {
+ continue;
+ }
+
// If C is not a horizontal whitespace, skip it.
if (*Ptr != ' ' && *Ptr != '\t') {
NewFile.push_back(*Ptr);
@@ -473,14 +490,14 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
static bool ReadCheckFile(SourceMgr &SM,
std::vector<CheckString> &CheckStrings) {
// Open the check file, and tell SourceMgr about it.
- std::string ErrorStr;
- MemoryBuffer *F =
- MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), &ErrorStr);
- if (F == 0) {
+ OwningPtr<MemoryBuffer> File;
+ if (error_code ec =
+ MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), File)) {
errs() << "Could not open check file '" << CheckFilename << "': "
- << ErrorStr << '\n';
+ << ec.message() << '\n';
return true;
}
+ MemoryBuffer *F = File.take();
// If we want to canonicalize whitespace, strip excess whitespace from the
// buffer containing the CHECK lines.
@@ -565,18 +582,20 @@ static bool ReadCheckFile(SourceMgr &SM,
std::swap(NotMatches, CheckStrings.back().NotStrings);
}
+ // Add an EOF pattern for any trailing CHECK-NOTs.
+ if (!NotMatches.empty()) {
+ CheckStrings.push_back(CheckString(Pattern(true),
+ SMLoc::getFromPointer(Buffer.data()),
+ false));
+ std::swap(NotMatches, CheckStrings.back().NotStrings);
+ }
+
if (CheckStrings.empty()) {
errs() << "error: no check strings found with prefix '" << CheckPrefix
<< ":'\n";
return true;
}
- if (!NotMatches.empty()) {
- errs() << "error: '" << CheckPrefix
- << "-NOT:' not supported after last check line.\n";
- return true;
- }
-
return false;
}
@@ -631,15 +650,20 @@ int main(int argc, char **argv) {
return 2;
// Open the file to check and add it to SourceMgr.
- std::string ErrorStr;
- MemoryBuffer *F =
- MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr);
- if (F == 0) {
+ OwningPtr<MemoryBuffer> File;
+ if (error_code ec =
+ MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) {
errs() << "Could not open input file '" << InputFilename << "': "
- << ErrorStr << '\n';
+ << ec.message() << '\n';
return true;
}
+ MemoryBuffer *F = File.take();
+ if (F->getBufferSize() == 0) {
+ errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
+ return 1;
+ }
+
// Remove duplicate spaces in the input file if requested.
if (!NoCanonicalizeWhiteSpace)
F = CanonicalizeInputFile(F);
@@ -662,10 +686,11 @@ int main(int argc, char **argv) {
// Find StrNo in the file.
size_t MatchLen = 0;
- Buffer = Buffer.substr(CheckStr.Pat.Match(Buffer, MatchLen, VariableTable));
+ size_t MatchPos = CheckStr.Pat.Match(Buffer, MatchLen, VariableTable);
+ Buffer = Buffer.substr(MatchPos);
// If we didn't find a match, reject the input.
- if (Buffer.empty()) {
+ if (MatchPos == StringRef::npos) {
PrintCheckFailed(SM, CheckStr, SearchFrom, VariableTable);
return 1;
}
diff --git a/utils/FileCheck/Makefile b/utils/FileCheck/Makefile
index f1af5b649e7a..268b7bc919a1 100644
--- a/utils/FileCheck/Makefile
+++ b/utils/FileCheck/Makefile
@@ -1,15 +1,15 @@
##===- utils/FileCheck/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 = FileCheck
-USEDLIBS = LLVMSupport.a LLVMSystem.a
+USEDLIBS = LLVMSupport.a
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/utils/FileUpdate/CMakeLists.txt b/utils/FileUpdate/CMakeLists.txt
index bacbd16b90f9..5dda49e0e4c5 100644
--- a/utils/FileUpdate/CMakeLists.txt
+++ b/utils/FileUpdate/CMakeLists.txt
@@ -2,7 +2,7 @@ add_executable(FileUpdate
FileUpdate.cpp
)
-target_link_libraries(FileUpdate LLVMSupport LLVMSystem)
+target_link_libraries(FileUpdate LLVMSupport)
if( MINGW )
target_link_libraries(FileUpdate imagehlp psapi)
endif( MINGW )
diff --git a/utils/FileUpdate/FileUpdate.cpp b/utils/FileUpdate/FileUpdate.cpp
index 2cf366fa55f8..3ea1e4f306ee 100644
--- a/utils/FileUpdate/FileUpdate.cpp
+++ b/utils/FileUpdate/FileUpdate.cpp
@@ -15,9 +15,11 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
using namespace llvm;
static cl::opt<bool>
@@ -42,17 +44,16 @@ int main(int argc, char **argv) {
}
// Get the input data.
- std::string ErrorStr;
- MemoryBuffer *In =
- MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr);
- if (In == 0) {
+ OwningPtr<MemoryBuffer> In;
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) {
errs() << argv[0] << ": error: Unable to get input '"
- << InputFilename << "': " << ErrorStr << '\n';
+ << InputFilename << "': " << ec.message() << '\n';
return 1;
}
// Get the output data.
- MemoryBuffer *Out = MemoryBuffer::getFile(OutputFilename.c_str(), &ErrorStr);
+ OwningPtr<MemoryBuffer> Out;
+ MemoryBuffer::getFile(OutputFilename.c_str(), Out);
// If the output exists and the contents match, we are done.
if (Out && In->getBufferSize() == Out->getBufferSize() &&
@@ -64,12 +65,11 @@ int main(int argc, char **argv) {
return 0;
}
- delete Out;
-
// Otherwise, overwrite the output.
if (!Quiet)
errs() << argv[0] << ": Updating '" << OutputFilename
<< "', contents changed.\n";
+ std::string ErrorStr;
tool_output_file OutStream(OutputFilename.c_str(), ErrorStr,
raw_fd_ostream::F_Binary);
if (!ErrorStr.empty()) {
diff --git a/utils/FileUpdate/Makefile b/utils/FileUpdate/Makefile
index 5b545c207297..1e6c0a838c27 100644
--- a/utils/FileUpdate/Makefile
+++ b/utils/FileUpdate/Makefile
@@ -1,15 +1,15 @@
##===- utils/FileUpdate/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 = FileUpdate
-USEDLIBS = LLVMSupport.a LLVMSystem.a
+USEDLIBS = LLVMSupport.a
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/utils/GenLibDeps.pl b/utils/GenLibDeps.pl
index f1f7e72bc1a5..ca852adfcc0d 100755
--- a/utils/GenLibDeps.pl
+++ b/utils/GenLibDeps.pl
@@ -107,7 +107,6 @@ if ($PEROBJ) {
$libpath =~ s/^TransformUtils/Transforms\/Utils/;
$libpath =~ s/^ipa/Analysis\/IPA/;
$libpath =~ s/^ipo/Transforms\/IPO/;
- $libpath =~ s/^pic16passes/Target\/PIC16\/PIC16Passes/;
$libpath = "lib/".$libpath."/";
open DEFS, "$nmPath -sg $Directory/$lib|";
while (<DEFS>) {
@@ -150,7 +149,6 @@ if ($PEROBJ) {
$libpath =~ s/^TransformUtils/Transforms\/Utils/;
$libpath =~ s/^ipa/Analysis\/IPA/;
$libpath =~ s/^ipo/Transforms\/IPO/;
- $libpath =~ s/^pic16passes/Target\/PIC16\/PIC16Passes/;
$libpath = "lib/".$libpath."/";
open UDEFS, "$nmPath -Aup $Directory/$lib|";
while (<UDEFS>) {
diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath
new file mode 100755
index 000000000000..326231c9e5d4
--- /dev/null
+++ b/utils/GetRepositoryPath
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: $0 <source root>"
+ echo " Prints the source control repository path of the given source"
+ echo " directory, the exact format of the revision string depends on the"
+ echo " source control system. If the source control system isn't known,"
+ echo " the output is empty and the exit code is 1."
+ exit 1
+}
+
+if [ $# != 1 ] || [ ! -d $1 ]; then
+ usage;
+fi
+
+cd $1
+if [ -d .svn ]; then
+ svn info | grep 'URL:' | cut -d: -f2-
+elif [ -d .git/svn ]; then
+ git svn info | grep 'URL:' | cut -d: -f2-
+elif [ -d .git ]; then
+ git remote -v | grep 'fetch' | awk '{ print $2 }'
+else
+ exit 1;
+fi
+
+exit 0
diff --git a/utils/GetSourceVersion b/utils/GetSourceVersion
index b25f2f97736b..cbed7daf5b61 100755
--- a/utils/GetSourceVersion
+++ b/utils/GetSourceVersion
@@ -1,12 +1,12 @@
#!/bin/sh
usage() {
- echo "usage: $0 <source root>"
- echo " Prints the source control revision of the given source directory,"
- echo " the exact format of the revision string depends on the source "
- echo " control system. If the source control system isn't known, the output"
- echo " is empty and the exit code is 1."
- exit 1
+ echo "usage: $0 <source root>"
+ echo " Prints the source control revision of the given source directory,"
+ echo " the exact format of the revision string depends on the source "
+ echo " control system. If the source control system isn't known, the output"
+ echo " is empty and the exit code is 1."
+ exit 1
}
if [ $# != 1 ] || [ ! -d $1 ]; then
@@ -15,13 +15,13 @@ fi
cd $1
if [ -d .svn ]; then
- svnversion
+ svnversion | sed -e "s#\([0-9]*\)[A-Z]*#\1#"
elif [ -d .git/svn ]; then
- git svn info | grep 'Revision:' | cut -d: -f2-
+ git svn info | grep 'Revision:' | cut -d: -f2-
elif [ -d .git ]; then
- git log -1 --pretty=format:%H
+ git log -1 --pretty=format:%H
else
- exit 1;
+ exit 1;
fi
exit 0
diff --git a/utils/KillTheDoctor/CMakeLists.txt b/utils/KillTheDoctor/CMakeLists.txt
new file mode 100644
index 000000000000..99c671e74af9
--- /dev/null
+++ b/utils/KillTheDoctor/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(KillTheDoctor
+ KillTheDoctor.cpp
+ )
+
+target_link_libraries(KillTheDoctor LLVMSupport)
diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp
new file mode 100644
index 000000000000..7a89dd379b70
--- /dev/null
+++ b/utils/KillTheDoctor/KillTheDoctor.cpp
@@ -0,0 +1,596 @@
+//===- KillTheDoctor - Prevent Dr. Watson from stopping tests ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program provides an extremely hacky way to stop Dr. Watson from starting
+// due to unhandled exceptions in child processes.
+//
+// This simply starts the program named in the first positional argument with
+// the arguments following it under a debugger. All this debugger does is catch
+// any unhandled exceptions thrown in the child process and close the program
+// (and hopefully tells someone about it).
+//
+// This also provides another really hacky method to prevent assert dialog boxes
+// from popping up. When --no-user32 is passed, if any process loads user32.dll,
+// we assume it is trying to call MessageBoxEx and terminate it. The proper way
+// to do this would be to actually set a break point, but there's quite a bit
+// of code involved to get the address of MessageBoxEx in the remote process's
+// address space due to Address space layout randomization (ASLR). This can be
+// added if it's ever actually needed.
+//
+// If the subprocess exits for any reason other than successful termination, -1
+// is returned. If the process exits normally the value it returned is returned.
+//
+// I hate Windows.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/type_traits.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
+#include <algorithm>
+#include <cerrno>
+#include <cstdlib>
+#include <map>
+#include <string>
+#include <Windows.h>
+#include <WinError.h>
+#include <Dbghelp.h>
+#include <psapi.h>
+using namespace llvm;
+
+#undef max
+
+namespace {
+ cl::opt<std::string> ProgramToRun(cl::Positional,
+ cl::desc("<program to run>"));
+ cl::list<std::string> Argv(cl::ConsumeAfter,
+ cl::desc("<program arguments>..."));
+ cl::opt<bool> TraceExecution("x",
+ cl::desc("Print detailed output about what is being run to stderr."));
+ cl::opt<unsigned> Timeout("t", cl::init(0),
+ cl::desc("Set maximum runtime in seconds. Defaults to infinite."));
+ cl::opt<bool> NoUser32("no-user32",
+ cl::desc("Terminate process if it loads user32.dll."));
+
+ StringRef ToolName;
+
+ template <typename HandleType>
+ class ScopedHandle {
+ typedef typename HandleType::handle_type handle_type;
+
+ handle_type Handle;
+
+ public:
+ ScopedHandle()
+ : Handle(HandleType::GetInvalidHandle()) {}
+
+ explicit ScopedHandle(handle_type handle)
+ : Handle(handle) {}
+
+ ~ScopedHandle() {
+ HandleType::Destruct(Handle);
+ }
+
+ ScopedHandle& operator=(handle_type handle) {
+ // Cleanup current handle.
+ if (!HandleType::isValid(Handle))
+ HandleType::Destruct(Handle);
+ Handle = handle;
+ return *this;
+ }
+
+ operator bool() const {
+ return HandleType::isValid(Handle);
+ }
+
+ operator handle_type() {
+ return Handle;
+ }
+ };
+
+ // This implements the most common handle in the Windows API.
+ struct CommonHandle {
+ typedef HANDLE handle_type;
+
+ static handle_type GetInvalidHandle() {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ static void Destruct(handle_type Handle) {
+ ::CloseHandle(Handle);
+ }
+
+ static bool isValid(handle_type Handle) {
+ return Handle != GetInvalidHandle();
+ }
+ };
+
+ struct FileMappingHandle {
+ typedef HANDLE handle_type;
+
+ static handle_type GetInvalidHandle() {
+ return NULL;
+ }
+
+ static void Destruct(handle_type Handle) {
+ ::CloseHandle(Handle);
+ }
+
+ static bool isValid(handle_type Handle) {
+ return Handle != GetInvalidHandle();
+ }
+ };
+
+ struct MappedViewOfFileHandle {
+ typedef LPVOID handle_type;
+
+ static handle_type GetInvalidHandle() {
+ return NULL;
+ }
+
+ static void Destruct(handle_type Handle) {
+ ::UnmapViewOfFile(Handle);
+ }
+
+ static bool isValid(handle_type Handle) {
+ return Handle != GetInvalidHandle();
+ }
+ };
+
+ struct ProcessHandle : CommonHandle {};
+ struct ThreadHandle : CommonHandle {};
+ struct TokenHandle : CommonHandle {};
+ struct FileHandle : CommonHandle {};
+
+ typedef ScopedHandle<FileMappingHandle> FileMappingScopedHandle;
+ typedef ScopedHandle<MappedViewOfFileHandle> MappedViewOfFileScopedHandle;
+ typedef ScopedHandle<ProcessHandle> ProcessScopedHandle;
+ typedef ScopedHandle<ThreadHandle> ThreadScopedHandle;
+ typedef ScopedHandle<TokenHandle> TokenScopedHandle;
+ typedef ScopedHandle<FileHandle> FileScopedHandle;
+}
+
+static error_code GetFileNameFromHandle(HANDLE FileHandle,
+ std::string& Name) {
+ char Filename[MAX_PATH+1];
+ bool Sucess = false;
+ Name.clear();
+
+ // Get the file size.
+ LARGE_INTEGER FileSize;
+ Sucess = ::GetFileSizeEx(FileHandle, &FileSize);
+
+ if (!Sucess)
+ return windows_error(::GetLastError());
+
+ // Create a file mapping object.
+ FileMappingScopedHandle FileMapping(
+ ::CreateFileMappingA(FileHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 1,
+ NULL));
+
+ if (!FileMapping)
+ return windows_error(::GetLastError());
+
+ // Create a file mapping to get the file name.
+ MappedViewOfFileScopedHandle MappedFile(
+ ::MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 1));
+
+ if (!MappedFile)
+ return windows_error(::GetLastError());
+
+ Sucess = ::GetMappedFileNameA(::GetCurrentProcess(),
+ MappedFile,
+ Filename,
+ array_lengthof(Filename) - 1);
+
+ if (!Sucess)
+ return windows_error(::GetLastError());
+ else {
+ Name = Filename;
+ return windows_error::success;
+ }
+}
+
+static std::string QuoteProgramPathIfNeeded(StringRef Command) {
+ if (Command.find_first_of(' ') == StringRef::npos)
+ return Command;
+ else {
+ std::string ret;
+ ret.reserve(Command.size() + 3);
+ ret.push_back('"');
+ ret.append(Command.begin(), Command.end());
+ ret.push_back('"');
+ return ret;
+ }
+}
+
+/// @brief Find program using shell lookup rules.
+/// @param Program This is either an absolute path, relative path, or simple a
+/// program name. Look in PATH for any programs that match. If no
+/// extension is present, try all extensions in PATHEXT.
+/// @return If ec == errc::success, The absolute path to the program. Otherwise
+/// the return value is undefined.
+static std::string FindProgram(const std::string &Program, error_code &ec) {
+ char PathName[MAX_PATH + 1];
+ typedef SmallVector<StringRef, 12> pathext_t;
+ pathext_t pathext;
+ // Check for the program without an extension (in case it already has one).
+ pathext.push_back("");
+ SplitString(std::getenv("PATHEXT"), pathext, ";");
+
+ for (pathext_t::iterator i = pathext.begin(), e = pathext.end(); i != e; ++i){
+ SmallString<5> ext;
+ for (std::size_t ii = 0, e = i->size(); ii != e; ++ii)
+ ext.push_back(::tolower((*i)[ii]));
+ LPCSTR Extension = NULL;
+ if (ext.size() && ext[0] == '.')
+ Extension = ext.c_str();
+ DWORD length = ::SearchPathA(NULL,
+ Program.c_str(),
+ Extension,
+ array_lengthof(PathName),
+ PathName,
+ NULL);
+ if (length == 0)
+ ec = windows_error(::GetLastError());
+ else if (length > array_lengthof(PathName)) {
+ // This may have been the file, return with error.
+ ec = windows_error::buffer_overflow;
+ break;
+ } else {
+ // We found the path! Return it.
+ ec = windows_error::success;
+ break;
+ }
+ }
+
+ // Make sure PathName is valid.
+ PathName[MAX_PATH] = 0;
+ return PathName;
+}
+
+static error_code EnableDebugPrivileges() {
+ HANDLE TokenHandle;
+ BOOL success = ::OpenProcessToken(::GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+ &TokenHandle);
+ if (!success)
+ return windows_error(::GetLastError());
+
+ TokenScopedHandle Token(TokenHandle);
+ TOKEN_PRIVILEGES TokenPrivileges;
+ LUID LocallyUniqueID;
+
+ success = ::LookupPrivilegeValueA(NULL,
+ SE_DEBUG_NAME,
+ &LocallyUniqueID);
+ if (!success)
+ return windows_error(::GetLastError());
+
+ TokenPrivileges.PrivilegeCount = 1;
+ TokenPrivileges.Privileges[0].Luid = LocallyUniqueID;
+ TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ success = ::AdjustTokenPrivileges(Token,
+ FALSE,
+ &TokenPrivileges,
+ sizeof(TOKEN_PRIVILEGES),
+ NULL,
+ NULL);
+ // The value of success is basically useless. Either way we are just returning
+ // the value of ::GetLastError().
+ return windows_error(::GetLastError());
+}
+
+static StringRef ExceptionCodeToString(DWORD ExceptionCode) {
+ switch(ExceptionCode) {
+ case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION";
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
+ case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT";
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ return "EXCEPTION_DATATYPE_MISALIGNMENT";
+ case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND";
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
+ case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT";
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ return "EXCEPTION_FLT_INVALID_OPERATION";
+ case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW";
+ case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK";
+ case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW";
+ case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION";
+ case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR";
+ case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO";
+ case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW";
+ case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION";
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
+ case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION";
+ case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP";
+ case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW";
+ default: return "<unknown>";
+ }
+}
+
+int main(int argc, char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ ToolName = argv[0];
+
+ cl::ParseCommandLineOptions(argc, argv, "Dr. Watson Assassin.\n");
+ if (ProgramToRun.size() == 0) {
+ cl::PrintHelpMessage();
+ return -1;
+ }
+
+ if (Timeout > std::numeric_limits<uint32_t>::max() / 1000) {
+ errs() << ToolName << ": Timeout value too large, must be less than: "
+ << std::numeric_limits<uint32_t>::max() / 1000
+ << '\n';
+ return -1;
+ }
+
+ std::string CommandLine(ProgramToRun);
+
+ error_code ec;
+ ProgramToRun = FindProgram(ProgramToRun, ec);
+ if (ec) {
+ errs() << ToolName << ": Failed to find program: '" << CommandLine
+ << "': " << ec.message() << '\n';
+ return -1;
+ }
+
+ if (TraceExecution)
+ errs() << ToolName << ": Found Program: " << ProgramToRun << '\n';
+
+ for (std::vector<std::string>::iterator i = Argv.begin(),
+ e = Argv.end();
+ i != e; ++i) {
+ CommandLine.push_back(' ');
+ CommandLine.append(*i);
+ }
+
+ if (TraceExecution)
+ errs() << ToolName << ": Program Image Path: " << ProgramToRun << '\n'
+ << ToolName << ": Command Line: " << CommandLine << '\n';
+
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInfo;
+ std::memset(&StartupInfo, 0, sizeof(StartupInfo));
+ StartupInfo.cb = sizeof(StartupInfo);
+ std::memset(&ProcessInfo, 0, sizeof(ProcessInfo));
+
+ // Set error mode to not display any message boxes. The child process inherits
+ // this.
+ ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+ ::_set_error_mode(_OUT_TO_STDERR);
+
+ BOOL success = ::CreateProcessA(ProgramToRun.c_str(),
+ LPSTR(CommandLine.c_str()),
+ NULL,
+ NULL,
+ FALSE,
+ DEBUG_PROCESS,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInfo);
+ if (!success) {
+ errs() << ToolName << ": Failed to run program: '" << ProgramToRun
+ << "': " << error_code(windows_error(::GetLastError())).message()
+ << '\n';
+ return -1;
+ }
+
+ // Make sure ::CloseHandle is called on exit.
+ std::map<DWORD, HANDLE> ProcessIDToHandle;
+
+ DEBUG_EVENT DebugEvent;
+ std::memset(&DebugEvent, 0, sizeof(DebugEvent));
+ DWORD dwContinueStatus = DBG_CONTINUE;
+
+ // Run the program under the debugger until either it exits, or throws an
+ // exception.
+ if (TraceExecution)
+ errs() << ToolName << ": Debugging...\n";
+
+ while(true) {
+ DWORD TimeLeft = INFINITE;
+ if (Timeout > 0) {
+ FILETIME CreationTime, ExitTime, KernelTime, UserTime;
+ ULARGE_INTEGER a, b;
+ success = ::GetProcessTimes(ProcessInfo.hProcess,
+ &CreationTime,
+ &ExitTime,
+ &KernelTime,
+ &UserTime);
+ if (!success) {
+ ec = windows_error(::GetLastError());
+
+ errs() << ToolName << ": Failed to get process times: "
+ << ec.message() << '\n';
+ return -1;
+ }
+ a.LowPart = KernelTime.dwLowDateTime;
+ a.HighPart = KernelTime.dwHighDateTime;
+ b.LowPart = UserTime.dwLowDateTime;
+ b.HighPart = UserTime.dwHighDateTime;
+ // Convert 100-nanosecond units to milliseconds.
+ uint64_t TotalTimeMiliseconds = (a.QuadPart + b.QuadPart) / 10000;
+ // Handle the case where the process has been running for more than 49
+ // days.
+ if (TotalTimeMiliseconds > std::numeric_limits<uint32_t>::max()) {
+ errs() << ToolName << ": Timeout Failed: Process has been running for"
+ "more than 49 days.\n";
+ return -1;
+ }
+
+ // We check with > instead of using Timeleft because if
+ // TotalTimeMiliseconds is greater than Timeout * 1000, TimeLeft would
+ // underflow.
+ if (TotalTimeMiliseconds > (Timeout * 1000)) {
+ errs() << ToolName << ": Process timed out.\n";
+ ::TerminateProcess(ProcessInfo.hProcess, -1);
+ // Otherwise other stuff starts failing...
+ return -1;
+ }
+
+ TimeLeft = (Timeout * 1000) - static_cast<uint32_t>(TotalTimeMiliseconds);
+ }
+ success = WaitForDebugEvent(&DebugEvent, TimeLeft);
+
+ if (!success) {
+ ec = windows_error(::GetLastError());
+
+ if (ec == errc::timed_out) {
+ errs() << ToolName << ": Process timed out.\n";
+ ::TerminateProcess(ProcessInfo.hProcess, -1);
+ // Otherwise other stuff starts failing...
+ return -1;
+ }
+
+ errs() << ToolName << ": Failed to wait for debug event in program: '"
+ << ProgramToRun << "': " << ec.message() << '\n';
+ return -1;
+ }
+
+ switch(DebugEvent.dwDebugEventCode) {
+ case CREATE_PROCESS_DEBUG_EVENT:
+ // Make sure we remove the handle on exit.
+ if (TraceExecution)
+ errs() << ToolName << ": Debug Event: CREATE_PROCESS_DEBUG_EVENT\n";
+ ProcessIDToHandle[DebugEvent.dwProcessId] =
+ DebugEvent.u.CreateProcessInfo.hProcess;
+ ::CloseHandle(DebugEvent.u.CreateProcessInfo.hFile);
+ break;
+ case EXIT_PROCESS_DEBUG_EVENT: {
+ if (TraceExecution)
+ errs() << ToolName << ": Debug Event: EXIT_PROCESS_DEBUG_EVENT\n";
+
+ // If this is the process we originally created, exit with its exit
+ // code.
+ if (DebugEvent.dwProcessId == ProcessInfo.dwProcessId)
+ return DebugEvent.u.ExitProcess.dwExitCode;
+
+ // Otherwise cleanup any resources we have for it.
+ std::map<DWORD, HANDLE>::iterator ExitingProcess =
+ ProcessIDToHandle.find(DebugEvent.dwProcessId);
+ if (ExitingProcess == ProcessIDToHandle.end()) {
+ errs() << ToolName << ": Got unknown process id!\n";
+ return -1;
+ }
+ ::CloseHandle(ExitingProcess->second);
+ ProcessIDToHandle.erase(ExitingProcess);
+ }
+ break;
+ case CREATE_THREAD_DEBUG_EVENT:
+ ::CloseHandle(DebugEvent.u.CreateThread.hThread);
+ break;
+ case LOAD_DLL_DEBUG_EVENT: {
+ // Cleanup the file handle.
+ FileScopedHandle DLLFile(DebugEvent.u.LoadDll.hFile);
+ std::string DLLName;
+ ec = GetFileNameFromHandle(DLLFile, DLLName);
+ if (ec) {
+ DLLName = "<failed to get file name from file handle> : ";
+ DLLName += ec.message();
+ }
+ if (TraceExecution) {
+ errs() << ToolName << ": Debug Event: LOAD_DLL_DEBUG_EVENT\n";
+ errs().indent(ToolName.size()) << ": DLL Name : " << DLLName << '\n';
+ }
+
+ if (NoUser32 && sys::path::stem(DLLName) == "user32") {
+ // Program is loading user32.dll, in the applications we are testing,
+ // this only happens if an assert has fired. By now the message has
+ // already been printed, so simply close the program.
+ errs() << ToolName << ": user32.dll loaded!\n";
+ errs().indent(ToolName.size())
+ << ": This probably means that assert was called. Closing "
+ "program to prevent message box from popping up.\n";
+ dwContinueStatus = DBG_CONTINUE;
+ ::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1);
+ return -1;
+ }
+ }
+ break;
+ case EXCEPTION_DEBUG_EVENT: {
+ // Close the application if this exception will not be handled by the
+ // child application.
+ if (TraceExecution)
+ errs() << ToolName << ": Debug Event: EXCEPTION_DEBUG_EVENT\n";
+
+ EXCEPTION_DEBUG_INFO &Exception = DebugEvent.u.Exception;
+ if (Exception.dwFirstChance > 0) {
+ if (TraceExecution) {
+ errs().indent(ToolName.size()) << ": Debug Info : ";
+ errs() << "First chance exception at "
+ << Exception.ExceptionRecord.ExceptionAddress
+ << ", exception code: "
+ << ExceptionCodeToString(
+ Exception.ExceptionRecord.ExceptionCode)
+ << " (" << Exception.ExceptionRecord.ExceptionCode << ")\n";
+ }
+ dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
+ } else {
+ errs() << ToolName << ": Unhandled exception in: " << ProgramToRun
+ << "!\n";
+ errs().indent(ToolName.size()) << ": location: ";
+ errs() << Exception.ExceptionRecord.ExceptionAddress
+ << ", exception code: "
+ << ExceptionCodeToString(
+ Exception.ExceptionRecord.ExceptionCode)
+ << " (" << Exception.ExceptionRecord.ExceptionCode
+ << ")\n";
+ dwContinueStatus = DBG_CONTINUE;
+ ::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1);
+ return -1;
+ }
+ }
+ break;
+ default:
+ // Do nothing.
+ if (TraceExecution)
+ errs() << ToolName << ": Debug Event: <unknown>\n";
+ break;
+ }
+
+ success = ContinueDebugEvent(DebugEvent.dwProcessId,
+ DebugEvent.dwThreadId,
+ dwContinueStatus);
+ if (!success) {
+ ec = windows_error(::GetLastError());
+ errs() << ToolName << ": Failed to continue debugging program: '"
+ << ProgramToRun << "': " << ec.message() << '\n';
+ return -1;
+ }
+
+ dwContinueStatus = DBG_CONTINUE;
+ }
+
+ assert(0 && "Fell out of debug loop. This shouldn't be possible!");
+ return -1;
+}
diff --git a/utils/Makefile b/utils/Makefile
index 1a4dcca8c5ee..9d4dc5c2f90b 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -15,7 +15,7 @@ EXTRA_DIST := cgiplotNLT.pl check-each-file codegen-diff countloc.sh \
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 \
+ NightlyTestTemplate.html NLT.schema \
parseNLT.pl plotNLT.pl profile.pl \
webNLT.pl vim
diff --git a/utils/OldenDataRecover.pl b/utils/OldenDataRecover.pl
deleted file mode 100644
index 767839488b34..000000000000
--- a/utils/OldenDataRecover.pl
+++ /dev/null
@@ -1,37 +0,0 @@
-#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/PerfectShuffle.cpp b/utils/PerfectShuffle/PerfectShuffle.cpp
index b94a7d326d19..98f8f4cc0cab 100644
--- a/utils/PerfectShuffle/PerfectShuffle.cpp
+++ b/utils/PerfectShuffle/PerfectShuffle.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include <iostream>
+#include <iomanip>
#include <vector>
#include <cassert>
#include <cstdlib>
@@ -400,7 +401,7 @@ int main() {
// LHS, and 13 bits of RHS = 32 bits.
unsigned Val = (CostSat << 30) | (OpNum << 26) | (LHS << 13) | RHS;
- std::cout << " " << Val << "U,\t// ";
+ std::cout << " " << std::setw(10) << Val << "U, // ";
PrintMask(i, std::cout);
std::cout << ": Cost " << ShufTab[i].Cost;
std::cout << " " << (ShufTab[i].Op ? ShufTab[i].Op->getName() : "copy");
diff --git a/utils/TableGen/ARMDecoderEmitter.cpp b/utils/TableGen/ARMDecoderEmitter.cpp
index 03b01f6bdb74..a8de7452ea06 100644
--- a/utils/TableGen/ARMDecoderEmitter.cpp
+++ b/utils/TableGen/ARMDecoderEmitter.cpp
@@ -221,7 +221,7 @@ typedef enum {
#define BIT_WIDTH 32
// Forward declaration.
-class FilterChooser;
+class ARMFilterChooser;
// Representation of the instruction to work on.
typedef bit_value_t insn_t[BIT_WIDTH];
@@ -240,7 +240,7 @@ typedef bit_value_t insn_t[BIT_WIDTH];
/// the Filter/FilterChooser combo does not know how to distinguish among the
/// Opcodes assigned.
///
-/// An example of a conflcit is
+/// An example of a conflict is
///
/// Conflict:
/// 111101000.00........00010000....
@@ -262,9 +262,9 @@ typedef bit_value_t insn_t[BIT_WIDTH];
/// decoder could try to decode the even/odd register numbering and assign to
/// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a"
/// version and return the Opcode since the two have the same Asm format string.
-class Filter {
+class ARMFilter {
protected:
- FilterChooser *Owner; // points to the FilterChooser who owns this filter
+ ARMFilterChooser *Owner; // points to the FilterChooser who owns this filter
unsigned StartBit; // the starting bit position
unsigned NumBits; // number of bits to filter
bool Mixed; // a mixed region contains both set and unset bits
@@ -276,7 +276,7 @@ protected:
std::vector<unsigned> VariableInstructions;
// Map of well-known segment value to its delegate.
- std::map<unsigned, FilterChooser*> FilterChooserMap;
+ std::map<unsigned, ARMFilterChooser*> FilterChooserMap;
// Number of instructions which fall under FilteredInstructions category.
unsigned NumFiltered;
@@ -296,16 +296,17 @@ public:
}
// Return the filter chooser for the group of instructions without constant
// segment values.
- FilterChooser &getVariableFC() {
+ ARMFilterChooser &getVariableFC() {
assert(NumFiltered == 1);
assert(FilterChooserMap.size() == 1);
return *(FilterChooserMap.find((unsigned)-1)->second);
}
- Filter(const Filter &f);
- Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, bool mixed);
+ ARMFilter(const ARMFilter &f);
+ ARMFilter(ARMFilterChooser &owner, unsigned startBit, unsigned numBits,
+ bool mixed);
- ~Filter();
+ ~ARMFilter();
// Divides the decoding task into sub tasks and delegates them to the
// inferior FilterChooser's.
@@ -333,7 +334,7 @@ typedef enum {
ATTR_MIXED
} bitAttr_t;
-/// FilterChooser - FilterChooser chooses the best filter among a set of Filters
+/// ARMFilterChooser - FilterChooser chooses the best filter among a set of Filters
/// in order to perform the decoding of instructions at the current level.
///
/// Decoding proceeds from the top down. Based on the well-known encoding bits
@@ -348,11 +349,11 @@ typedef enum {
/// It is useful to think of a Filter as governing the switch stmts of the
/// decoding tree. And each case is delegated to an inferior FilterChooser to
/// decide what further remaining bits to look at.
-class FilterChooser {
+class ARMFilterChooser {
static TARGET_NAME_t TargetName;
protected:
- friend class Filter;
+ friend class ARMFilter;
// Vector of codegen instructions to choose our filter.
const std::vector<const CodeGenInstruction*> &AllInstructions;
@@ -361,14 +362,14 @@ protected:
const std::vector<unsigned> Opcodes;
// Vector of candidate filters.
- std::vector<Filter> Filters;
+ std::vector<ARMFilter> Filters;
// Array of bit values passed down from our parent.
// Set to all BIT_UNFILTERED's for Parent == NULL.
bit_value_t FilterBitValues[BIT_WIDTH];
// Links to the FilterChooser above us in the decoding tree.
- FilterChooser *Parent;
+ ARMFilterChooser *Parent;
// Index of the best filter from Filters.
int BestIndex;
@@ -376,13 +377,13 @@ protected:
public:
static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; }
- FilterChooser(const FilterChooser &FC) :
+ ARMFilterChooser(const ARMFilterChooser &FC) :
AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes),
Filters(FC.Filters), Parent(FC.Parent), BestIndex(FC.BestIndex) {
memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues));
}
- FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ ARMFilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
const std::vector<unsigned> &IDs) :
AllInstructions(Insts), Opcodes(IDs), Filters(), Parent(NULL),
BestIndex(-1) {
@@ -392,10 +393,10 @@ public:
doFilter();
}
- FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
- const std::vector<unsigned> &IDs,
- bit_value_t (&ParentFilterBitValues)[BIT_WIDTH],
- FilterChooser &parent) :
+ ARMFilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ const std::vector<unsigned> &IDs,
+ bit_value_t (&ParentFilterBitValues)[BIT_WIDTH],
+ ARMFilterChooser &parent) :
AllInstructions(Insts), Opcodes(IDs), Filters(), Parent(&parent),
BestIndex(-1) {
for (unsigned i = 0; i < BIT_WIDTH; ++i)
@@ -426,8 +427,9 @@ protected:
Insn[i] = bitFromBits(Bits, i);
// Set Inst{21} to 1 (wback) when IndexModeBits == IndexModeUpd.
- if (getByteField(*AllInstructions[Opcode]->TheDef, "IndexModeBits")
- == IndexModeUpd)
+ Record *R = AllInstructions[Opcode]->TheDef;
+ if (R->getValue("IndexModeBits") &&
+ getByteField(*R, "IndexModeBits") == IndexModeUpd)
Insn[21] = BIT_TRUE;
}
@@ -452,7 +454,7 @@ protected:
/// dumpFilterArray on each filter chooser up to the top level one.
void dumpStack(raw_ostream &o, const char *prefix);
- Filter &bestFilter() {
+ ARMFilter &bestFilter() {
assert(BestIndex != -1 && "BestIndex not set");
return Filters[BestIndex];
}
@@ -497,11 +499,12 @@ protected:
bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,unsigned Opc);
// Emits code to decode the singleton, and then to decode the rest.
- void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,Filter &Best);
+ void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ ARMFilter &Best);
// Assign a single filter and run with it.
- void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit,
- bool mixed);
+ void runSingleFilter(ARMFilterChooser &owner, unsigned startBit,
+ unsigned numBit, bool mixed);
// reportRegion is a helper function for filterProcessor to mark a region as
// eligible for use as a filter region.
@@ -530,7 +533,7 @@ protected:
// //
///////////////////////////
-Filter::Filter(const Filter &f) :
+ARMFilter::ARMFilter(const ARMFilter &f) :
Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed),
FilteredInstructions(f.FilteredInstructions),
VariableInstructions(f.VariableInstructions),
@@ -538,7 +541,7 @@ Filter::Filter(const Filter &f) :
LastOpcFiltered(f.LastOpcFiltered), NumVariable(f.NumVariable) {
}
-Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
+ARMFilter::ARMFilter(ARMFilterChooser &owner, unsigned startBit, unsigned numBits,
bool mixed) : Owner(&owner), StartBit(startBit), NumBits(numBits),
Mixed(mixed) {
assert(StartBit + NumBits - 1 < BIT_WIDTH);
@@ -575,8 +578,8 @@ Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
&& "Filter returns no instruction categories");
}
-Filter::~Filter() {
- std::map<unsigned, FilterChooser*>::iterator filterIterator;
+ARMFilter::~ARMFilter() {
+ std::map<unsigned, ARMFilterChooser*>::iterator filterIterator;
for (filterIterator = FilterChooserMap.begin();
filterIterator != FilterChooserMap.end();
filterIterator++) {
@@ -590,7 +593,7 @@ Filter::~Filter() {
// A special case arises when there's only one entry in the filtered
// instructions. In order to unambiguously decode the singleton, we need to
// match the remaining undecoded encoding bits against the singleton.
-void Filter::recurse() {
+void ARMFilter::recurse() {
std::map<uint64_t, std::vector<unsigned> >::const_iterator mapIterator;
bit_value_t BitValueArray[BIT_WIDTH];
@@ -606,12 +609,12 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for futher processing on this
// group of instructions whose segment values are variable.
- FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ FilterChooserMap.insert(std::pair<unsigned, ARMFilterChooser*>(
(unsigned)-1,
- new FilterChooser(Owner->AllInstructions,
- VariableInstructions,
- BitValueArray,
- *Owner)
+ new ARMFilterChooser(Owner->AllInstructions,
+ VariableInstructions,
+ BitValueArray,
+ *Owner)
));
}
@@ -638,18 +641,18 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for futher processing on this
// category of instructions.
- FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ FilterChooserMap.insert(std::pair<unsigned, ARMFilterChooser*>(
mapIterator->first,
- new FilterChooser(Owner->AllInstructions,
- mapIterator->second,
- BitValueArray,
- *Owner)
+ new ARMFilterChooser(Owner->AllInstructions,
+ mapIterator->second,
+ BitValueArray,
+ *Owner)
));
}
}
// Emit code to decode instructions given a segment or segments of bits.
-void Filter::emit(raw_ostream &o, unsigned &Indentation) {
+void ARMFilter::emit(raw_ostream &o, unsigned &Indentation) {
o.indent(Indentation) << "// Check Inst{";
if (NumBits > 1)
@@ -660,7 +663,7 @@ void Filter::emit(raw_ostream &o, unsigned &Indentation) {
o.indent(Indentation) << "switch (fieldFromInstruction(insn, "
<< StartBit << ", " << NumBits << ")) {\n";
- std::map<unsigned, FilterChooser*>::iterator filterIterator;
+ std::map<unsigned, ARMFilterChooser*>::iterator filterIterator;
bool DefaultCase = false;
for (filterIterator = FilterChooserMap.begin();
@@ -709,7 +712,7 @@ void Filter::emit(raw_ostream &o, unsigned &Indentation) {
// Returns the number of fanout produced by the filter. More fanout implies
// the filter distinguishes more categories of instructions.
-unsigned Filter::usefulness() const {
+unsigned ARMFilter::usefulness() const {
if (VariableInstructions.size())
return FilteredInstructions.size();
else
@@ -723,10 +726,10 @@ unsigned Filter::usefulness() const {
//////////////////////////////////
// Define the symbol here.
-TARGET_NAME_t FilterChooser::TargetName;
+TARGET_NAME_t ARMFilterChooser::TargetName;
// This provides an opportunity for target specific code emission.
-void FilterChooser::emitTopHook(raw_ostream &o) {
+void ARMFilterChooser::emitTopHook(raw_ostream &o) {
if (TargetName == TARGET_ARM) {
// Emit code that references the ARMFormat data type.
o << "static const ARMFormat ARMFormats[] = {\n";
@@ -747,7 +750,7 @@ void FilterChooser::emitTopHook(raw_ostream &o) {
}
// Emit the top level typedef and decodeInstruction() function.
-void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) {
+void ARMFilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) {
// Run the target specific emit hook.
emitTopHook(o);
@@ -801,7 +804,7 @@ void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) {
o << '\n';
- o.indent(Indentation) << "static uint16_t decodeInstruction(field_t insn) {\n";
+ o.indent(Indentation) <<"static uint16_t decodeInstruction(field_t insn) {\n";
++Indentation; ++Indentation;
// Emits code to decode the instructions.
@@ -818,7 +821,7 @@ void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) {
// This provides an opportunity for target specific code emission after
// emitTop().
-void FilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) {
+void ARMFilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) {
if (TargetName != TARGET_THUMB) return;
// Emit code that decodes the Thumb ISA.
@@ -843,7 +846,7 @@ void FilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) {
//
// Returns false if and on the first uninitialized bit value encountered.
// Returns true, otherwise.
-bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
+bool ARMFilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
unsigned StartBit, unsigned NumBits) const {
Field = 0;
@@ -860,7 +863,7 @@ bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
/// filter array as a series of chars.
-void FilterChooser::dumpFilterArray(raw_ostream &o,
+void ARMFilterChooser::dumpFilterArray(raw_ostream &o,
bit_value_t (&filter)[BIT_WIDTH]) {
unsigned bitIndex;
@@ -884,8 +887,8 @@ void FilterChooser::dumpFilterArray(raw_ostream &o,
/// dumpStack - dumpStack traverses the filter chooser chain and calls
/// dumpFilterArray on each filter chooser up to the top level one.
-void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
- FilterChooser *current = this;
+void ARMFilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
+ ARMFilterChooser *current = this;
while (current) {
o << prefix;
@@ -896,7 +899,7 @@ void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
}
// Called from Filter::recurse() when singleton exists. For debug purpose.
-void FilterChooser::SingletonExists(unsigned Opc) {
+void ARMFilterChooser::SingletonExists(unsigned Opc) {
insn_t Insn0;
insnWithID(Insn0, Opc);
@@ -923,7 +926,7 @@ void FilterChooser::SingletonExists(unsigned Opc) {
// This returns a list of undecoded bits of an instructions, for example,
// Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be
// decoded bits in order to verify that the instruction matches the Opcode.
-unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
+unsigned ARMFilterChooser::getIslands(std::vector<unsigned> &StartBits,
std::vector<unsigned> &EndBits, std::vector<uint64_t> &FieldVals,
insn_t &Insn) {
unsigned Num, BitNo;
@@ -983,7 +986,7 @@ unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
// Emits code to decode the singleton. Return true if we have matched all the
// well-known bits.
-bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+bool ARMFilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
unsigned Opc) {
std::vector<unsigned> StartBits;
std::vector<unsigned> EndBits;
@@ -1046,8 +1049,9 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
}
// Emits code to decode the singleton, and then to decode the rest.
-void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
- Filter &Best) {
+void ARMFilterChooser::emitSingletonDecoder(raw_ostream &o,
+ unsigned &Indentation,
+ ARMFilter &Best) {
unsigned Opc = Best.getSingletonOpc();
@@ -1063,10 +1067,11 @@ void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
// Assign a single filter and run with it. Top level API client can initialize
// with a single filter to start the filtering process.
-void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit,
- unsigned numBit, bool mixed) {
+void ARMFilterChooser::runSingleFilter(ARMFilterChooser &owner,
+ unsigned startBit,
+ unsigned numBit, bool mixed) {
Filters.clear();
- Filter F(*this, startBit, numBit, true);
+ ARMFilter F(*this, startBit, numBit, true);
Filters.push_back(F);
BestIndex = 0; // Sole Filter instance to choose from.
bestFilter().recurse();
@@ -1074,18 +1079,18 @@ void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit,
// reportRegion is a helper function for filterProcessor to mark a region as
// eligible for use as a filter region.
-void FilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit,
- unsigned BitIndex, bool AllowMixed) {
+void ARMFilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit,
+ unsigned BitIndex, bool AllowMixed) {
if (RA == ATTR_MIXED && AllowMixed)
- Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, true));
+ Filters.push_back(ARMFilter(*this, StartBit, BitIndex - StartBit, true));
else if (RA == ATTR_ALL_SET && !AllowMixed)
- Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, false));
+ Filters.push_back(ARMFilter(*this, StartBit, BitIndex - StartBit, false));
}
// FilterProcessor scans the well-known encoding bits of the instructions and
// builds up a list of candidate filters. It chooses the best filter and
// recursively descends down the decoding tree.
-bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
+bool ARMFilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
Filters.clear();
BestIndex = -1;
unsigned numInstructions = Opcodes.size();
@@ -1317,7 +1322,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
// Decides on the best configuration of filter(s) to use in order to decode
// the instructions. A conflict of instructions may occur, in which case we
// dump the conflict set to the standard error.
-void FilterChooser::doFilter() {
+void ARMFilterChooser::doFilter() {
unsigned Num = Opcodes.size();
assert(Num && "FilterChooser created with no instructions");
@@ -1350,7 +1355,7 @@ void FilterChooser::doFilter() {
// Emits code to decode our share of instructions. Returns true if the
// emitted code causes a return, which occurs if we know how to decode
// the instruction at this level or the instruction is not decodeable.
-bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
+bool ARMFilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
if (Opcodes.size() == 1)
// There is only one instruction in the set, which is great!
// Call emitSingletonDecoder() to see whether there are any remaining
@@ -1359,7 +1364,7 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
// Choose the best filter to do the decodings!
if (BestIndex != -1) {
- Filter &Best = bestFilter();
+ ARMFilter &Best = bestFilter();
if (Best.getNumFiltered() == 1)
emitSingletonDecoder(o, Indentation, Best);
else
@@ -1488,11 +1493,11 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
class ARMDecoderEmitter::ARMDEBackend {
public:
- ARMDEBackend(ARMDecoderEmitter &frontend) :
+ ARMDEBackend(ARMDecoderEmitter &frontend, RecordKeeper &Records) :
NumberedInstructions(),
Opcodes(),
Frontend(frontend),
- Target(),
+ Target(Records),
FC(NULL)
{
if (Target.getName() == "ARM")
@@ -1538,13 +1543,14 @@ protected:
std::vector<unsigned> Opcodes2;
ARMDecoderEmitter &Frontend;
CodeGenTarget Target;
- FilterChooser *FC;
+ ARMFilterChooser *FC;
TARGET_NAME_t TargetName;
};
-bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
- const CodeGenInstruction &CGI, TARGET_NAME_t TN) {
+bool ARMDecoderEmitter::
+ARMDEBackend::populateInstruction(const CodeGenInstruction &CGI,
+ TARGET_NAME_t TN) {
const Record &Def = *CGI.TheDef;
const StringRef Name = Def.getName();
uint8_t Form = getByteField(Def, "Form");
@@ -1559,6 +1565,10 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
// which is a better design and less fragile than the name matchings.
if (Bits.allInComplete()) return false;
+ // Ignore "asm parser only" instructions.
+ if (Def.getValueAsBit("isAsmParserOnly"))
+ return false;
+
if (TN == TARGET_ARM) {
// FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6?
if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") &&
@@ -1566,13 +1576,6 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
return false;
if (thumbInstruction(Form))
return false;
- if (Name.find("CMPz") != std::string::npos /* ||
- Name.find("CMNz") != std::string::npos */)
- return false;
-
- // Ignore pseudo instructions.
- if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9")
- return false;
// Tail calls are other patterns that generate existing instructions.
if (Name == "TCRETURNdi" || Name == "TCRETURNdiND" ||
@@ -1583,11 +1586,6 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
Name == "MOVr_TC")
return false;
- // VLDMQ/VSTMQ can be handled with the more generic VLDMD/VSTMD.
- if (Name == "VLDMQ" || Name == "VLDMQ_UPD" ||
- Name == "VSTMQ" || Name == "VSTMQ_UPD")
- return false;
-
//
// The following special cases are for conflict resolutions.
//
@@ -1610,13 +1608,13 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
// better off using the generic RSCri and RSCrs instructions.
if (Name == "RSCSri" || Name == "RSCSrs") return false;
- // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used
- // in the compiler to implement conditional moves. We can ignore them in
- // favor of their more generic versions of instructions.
- // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op).
- if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" ||
- Name == "FCPYScc" || Name == "FCPYDcc" ||
- Name == "FNEGScc" || Name == "FNEGDcc")
+ // MOVCCr, MOVCCs, MOVCCi, MOVCCi16, FCYPScc, FCYPDcc, FNEGScc, and
+ // FNEGDcc are used in the compiler to implement conditional moves.
+ // We can ignore them in favor of their more generic versions of
+ // instructions. See also SDNode *ARMDAGToDAGISel::Select(SDValue Op).
+ if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" ||
+ Name == "MOVCCi16" || Name == "FCPYScc" || Name == "FCPYDcc" ||
+ Name == "FNEGScc" || Name == "FNEGDcc")
return false;
// Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc.
@@ -1624,15 +1622,10 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
Name == "VNEGScc")
return false;
- // Ignore the *_sfp instructions when decoding. They are used by the
- // compiler to implement scalar floating point operations using vector
- // operations in order to work around some performance issues.
- if (Name.find("_sfp") != std::string::npos) return false;
-
- // LDM_RET is a special case of LDM (Load Multiple) where the registers
+ // LDMIA_RET is a special case of LDM (Load Multiple) where the registers
// loaded include the PC, causing a branch to a loaded address. Ignore
- // the LDM_RET instruction when decoding.
- if (Name == "LDM_RET") return false;
+ // the LDMIA_RET instruction when decoding.
+ if (Name == "LDMIA_RET") return false;
// Bcc is in a more generic form than B. Ignore B when decoding.
if (Name == "B") return false;
@@ -1671,18 +1664,17 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
// VREV64qf is equivalent to VREV64q32.
if (Name == "VREV64df" || Name == "VREV64qf") return false;
- // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d.
- // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q.
+ // VDUPLNfd is equivalent to VDUPLN32d.
+ // VDUPLNfq is equivalent to VDUPLN32q.
// VLD1df is equivalent to VLD1d32.
// VLD1qf is equivalent to VLD1q32.
// VLD2d64 is equivalent to VLD1q64.
// VST1df is equivalent to VST1d32.
// VST1qf is equivalent to VST1q32.
// VST2d64 is equivalent to VST1q64.
- if (Name == "VDUPLNfd" || Name == "VDUPfdf" ||
- Name == "VDUPLNfq" || Name == "VDUPfqf" ||
- Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" ||
- Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64")
+ if (Name == "VDUPLNfd" || Name == "VDUPLNfq" ||
+ Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" ||
+ Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64")
return false;
} else if (TN == TARGET_THUMB) {
if (!thumbInstruction(Form))
@@ -1696,12 +1688,8 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
if (Name == "tTPsoft" || Name == "t2TPsoft")
return false;
- // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi.
- if (Name == "tLEApcrel" || Name == "tLEApcrelJT")
- return false;
-
- // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing.
- if (Name == "t2LEApcrel")
+ // Ignore tADR, prefer tADDrPCi.
+ if (Name == "tADR")
return false;
// Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr.
@@ -1719,42 +1707,33 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
if (Name == "t2LDRDpci")
return false;
- // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen.
- if (Name == "t2TBB" || Name == "t2TBH")
- return false;
-
// Resolve conflicts:
//
// tBfar conflicts with tBLr9
- // tCMNz conflicts with tCMN (with assembly format strings being equal)
- // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto)
+ // tPOP_RET/t2LDMIA_RET conflict with tPOP/t2LDM (ditto)
// tMOVCCi conflicts with tMOVi8
// tMOVCCr conflicts with tMOVgpr2gpr
- // tBR_JTr conflicts with tBRIND
// tSpill conflicts with tSTRspi
// tLDRcp conflicts with tLDRspi
// tRestore conflicts with tLDRspi
- // t2LEApcrelJT conflicts with t2LEApcrel
+ // t2MOVCCi16 conflicts with tMOVi16
if (Name == "tBfar" ||
- /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" ||
- Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" ||
- Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" ||
- Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" ||
- Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" ||
+ Name == "tPOP_RET" || Name == "t2LDMIA_RET" ||
+ Name == "tMOVCCi" || Name == "tMOVCCr" ||
Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" ||
- Name == "t2LEApcrelJT")
+ Name == "t2MOVCCi16")
return false;
}
- // Dumps the instruction encoding format.
- switch (TargetName) {
- case TARGET_ARM:
- case TARGET_THUMB:
- DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form));
- break;
- }
-
DEBUG({
+ // Dumps the instruction encoding format.
+ switch (TargetName) {
+ case TARGET_ARM:
+ case TARGET_THUMB:
+ errs() << Name << " " << stringForARMFormat((ARMFormat)Form);
+ break;
+ }
+
errs() << " ";
// Dumps the instruction encoding bits.
@@ -1763,8 +1742,8 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
errs() << '\n';
// Dumps the list of operand info.
- for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
- CodeGenInstruction::OperandInfo Info = CGI.OperandList[i];
+ for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
+ const CGIOperandList::OperandInfo &Info = CGI.Operands[i];
const std::string &OperandName = Info.Name;
const Record &OperandDef = *Info.Rec;
@@ -1778,32 +1757,20 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
void ARMDecoderEmitter::ARMDEBackend::populateInstructions() {
getInstructionsByEnumValue(NumberedInstructions);
- uint16_t numUIDs = NumberedInstructions.size();
- uint16_t uid;
-
- const char *instClass = NULL;
-
- switch (TargetName) {
- case TARGET_ARM:
- instClass = "InstARM";
- break;
- default:
- assert(0 && "Unreachable code!");
- }
-
- for (uid = 0; uid < numUIDs; uid++) {
- // filter out intrinsics
- if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass))
- continue;
+ unsigned numUIDs = NumberedInstructions.size();
+ if (TargetName == TARGET_ARM) {
+ for (unsigned uid = 0; uid < numUIDs; uid++) {
+ // filter out intrinsics
+ if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM"))
+ continue;
- if (populateInstruction(*NumberedInstructions[uid], TargetName))
- Opcodes.push_back(uid);
- }
+ if (populateInstruction(*NumberedInstructions[uid], TargetName))
+ Opcodes.push_back(uid);
+ }
- // Special handling for the ARM chip, which supports two modes of execution.
- // This branch handles the Thumb opcodes.
- if (TargetName == TARGET_ARM) {
- for (uid = 0; uid < numUIDs; uid++) {
+ // Special handling for the ARM chip, which supports two modes of execution.
+ // This branch handles the Thumb opcodes.
+ for (unsigned uid = 0; uid < numUIDs; uid++) {
// filter out intrinsics
if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM")
&& !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb"))
@@ -1812,6 +1779,18 @@ void ARMDecoderEmitter::ARMDEBackend::populateInstructions() {
if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB))
Opcodes2.push_back(uid);
}
+
+ return;
+ }
+
+ // For other targets.
+ for (unsigned uid = 0; uid < numUIDs; uid++) {
+ Record *R = NumberedInstructions[uid]->TheDef;
+ if (R->getValueAsString("Namespace") == "TargetOpcode")
+ continue;
+
+ if (populateInstruction(*NumberedInstructions[uid], TargetName))
+ Opcodes.push_back(uid);
}
}
@@ -1826,25 +1805,25 @@ void ARMDecoderEmitter::ARMDEBackend::emit(raw_ostream &o) {
assert(0 && "Unreachable code!");
}
- o << "#include \"llvm/System/DataTypes.h\"\n";
+ o << "#include \"llvm/Support/DataTypes.h\"\n";
o << "#include <assert.h>\n";
o << '\n';
o << "namespace llvm {\n\n";
- FilterChooser::setTargetName(TargetName);
+ ARMFilterChooser::setTargetName(TargetName);
switch (TargetName) {
case TARGET_ARM: {
// Emit common utility and ARM ISA decoder.
- FC = new FilterChooser(NumberedInstructions, Opcodes);
+ FC = new ARMFilterChooser(NumberedInstructions, Opcodes);
// Reset indentation level.
unsigned Indentation = 0;
FC->emitTop(o, Indentation);
delete FC;
// Emit Thumb ISA decoder as well.
- FilterChooser::setTargetName(TARGET_THUMB);
- FC = new FilterChooser(NumberedInstructions, Opcodes2);
+ ARMFilterChooser::setTargetName(TARGET_THUMB);
+ FC = new ARMFilterChooser(NumberedInstructions, Opcodes2);
// Reset indentation level.
Indentation = 0;
FC->emitBot(o, Indentation);
@@ -1863,7 +1842,7 @@ void ARMDecoderEmitter::ARMDEBackend::emit(raw_ostream &o) {
void ARMDecoderEmitter::initBackend()
{
- Backend = new ARMDEBackend(*this);
+ Backend = new ARMDEBackend(*this, Records);
}
void ARMDecoderEmitter::run(raw_ostream &o)
diff --git a/utils/TableGen/ARMDecoderEmitter.h b/utils/TableGen/ARMDecoderEmitter.h
index 571a94778acb..1faeb91fae8a 100644
--- a/utils/TableGen/ARMDecoderEmitter.h
+++ b/utils/TableGen/ARMDecoderEmitter.h
@@ -17,7 +17,7 @@
#include "TableGenBackend.h"
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
namespace llvm {
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 558398648d2c..e3def4185238 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -8,7 +8,11 @@
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a target specifier matcher for converting parsed
-// assembly operands in the MCInst structures.
+// assembly operands in the MCInst structures. It also emits a matcher for
+// custom operand parsing.
+//
+// Converting assembly operands into MCInst structures
+// ---------------------------------------------------
//
// The input to the target specific matcher is a list of literal tokens and
// operands. The target specific parser should generally eliminate any syntax
@@ -20,7 +24,7 @@
// Some example inputs, for X86:
// 'addl' (immediate ...) (register ...)
// 'add' (immediate ...) (memory ...)
-// 'call' '*' %epc
+// 'call' '*' %epc
//
// The assembly matcher is responsible for converting this input into a precise
// machine instruction (i.e., an instruction with a well defined encoding). This
@@ -63,26 +67,47 @@
// In addition, the subset relation amongst classes induces a partial order
// on such tuples, which we use to resolve ambiguities.
//
-// FIXME: What do we do if a crazy case shows up where this is the wrong
-// resolution?
-//
// 2. The input can now be treated as a tuple of classes (static tokens are
// simple singleton sets). Each such tuple should generally map to a single
// instruction (we currently ignore cases where this isn't true, whee!!!),
// which we can emit a simple matcher for.
//
+// Custom Operand Parsing
+// ----------------------
+//
+// Some targets need a custom way to parse operands, some specific instructions
+// can contain arguments that can represent processor flags and other kinds of
+// identifiers that need to be mapped to specific valeus in the final encoded
+// instructions. The target specific custom operand parsing works in the
+// following way:
+//
+// 1. A operand match table is built, each entry contains a mnemonic, an
+// operand class, a mask for all operand positions for that same
+// class/mnemonic and target features to be checked while trying to match.
+//
+// 2. The operand matcher will try every possible entry with the same
+// mnemonic and will check if the target feature for this mnemonic also
+// matches. After that, if the operand to be matched has its index
+// present in the mask, a successfull match occurs. Otherwise, fallback
+// to the regular operand parsing.
+//
+// 3. For a match success, each operand class that has a 'ParserMethod'
+// becomes part of a switch from where the custom method is called.
+//
//===----------------------------------------------------------------------===//
#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
#include "Record.h"
+#include "StringMatcher.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
-#include <list>
#include <map>
#include <set>
using namespace llvm;
@@ -91,197 +116,8 @@ static cl::opt<std::string>
MatchPrefix("match-prefix", cl::init(""),
cl::desc("Only match instructions with the given prefix"));
-/// FlattenVariants - Flatten an .td file assembly string by selecting the
-/// variant at index \arg N.
-static std::string FlattenVariants(const std::string &AsmString,
- unsigned N) {
- StringRef Cur = AsmString;
- std::string Res = "";
-
- for (;;) {
- // Find the start of the next variant string.
- size_t VariantsStart = 0;
- for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)
- if (Cur[VariantsStart] == '{' &&
- (VariantsStart == 0 || (Cur[VariantsStart-1] != '$' &&
- Cur[VariantsStart-1] != '\\')))
- break;
-
- // Add the prefix to the result.
- Res += Cur.slice(0, VariantsStart);
- if (VariantsStart == Cur.size())
- break;
-
- ++VariantsStart; // Skip the '{'.
-
- // Scan to the end of the variants string.
- size_t VariantsEnd = VariantsStart;
- unsigned NestedBraces = 1;
- for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {
- if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') {
- if (--NestedBraces == 0)
- break;
- } else if (Cur[VariantsEnd] == '{')
- ++NestedBraces;
- }
-
- // Select the Nth variant (or empty).
- StringRef Selection = Cur.slice(VariantsStart, VariantsEnd);
- for (unsigned i = 0; i != N; ++i)
- Selection = Selection.split('|').second;
- Res += Selection.split('|').first;
-
- assert(VariantsEnd != Cur.size() &&
- "Unterminated variants in assembly string!");
- Cur = Cur.substr(VariantsEnd + 1);
- }
-
- return Res;
-}
-
-/// TokenizeAsmString - Tokenize a simplified assembly string.
-static void TokenizeAsmString(StringRef AsmString,
- SmallVectorImpl<StringRef> &Tokens) {
- unsigned Prev = 0;
- bool InTok = true;
- for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
- switch (AsmString[i]) {
- case '[':
- case ']':
- case '*':
- case '!':
- case ' ':
- case '\t':
- case ',':
- if (InTok) {
- Tokens.push_back(AsmString.slice(Prev, i));
- InTok = false;
- }
- if (!isspace(AsmString[i]) && AsmString[i] != ',')
- Tokens.push_back(AsmString.substr(i, 1));
- Prev = i + 1;
- break;
-
- case '\\':
- if (InTok) {
- Tokens.push_back(AsmString.slice(Prev, i));
- InTok = false;
- }
- ++i;
- assert(i != AsmString.size() && "Invalid quoted character");
- Tokens.push_back(AsmString.substr(i, 1));
- Prev = i + 1;
- break;
-
- case '$': {
- // If this isn't "${", treat like a normal token.
- if (i + 1 == AsmString.size() || AsmString[i + 1] != '{') {
- if (InTok) {
- Tokens.push_back(AsmString.slice(Prev, i));
- InTok = false;
- }
- Prev = i;
- break;
- }
-
- if (InTok) {
- Tokens.push_back(AsmString.slice(Prev, i));
- InTok = false;
- }
-
- StringRef::iterator End =
- std::find(AsmString.begin() + i, AsmString.end(), '}');
- assert(End != AsmString.end() && "Missing brace in operand reference!");
- size_t EndPos = End - AsmString.begin();
- Tokens.push_back(AsmString.slice(i, EndPos+1));
- Prev = EndPos + 1;
- i = EndPos;
- break;
- }
-
- case '.':
- if (InTok) {
- Tokens.push_back(AsmString.slice(Prev, i));
- }
- Prev = i;
- InTok = true;
- break;
-
- default:
- InTok = true;
- }
- }
- if (InTok && Prev != AsmString.size())
- Tokens.push_back(AsmString.substr(Prev));
-}
-
-static bool IsAssemblerInstruction(StringRef Name,
- const CodeGenInstruction &CGI,
- const SmallVectorImpl<StringRef> &Tokens) {
- // Ignore "codegen only" instructions.
- if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
- return false;
-
- // Ignore pseudo ops.
- //
- // FIXME: This is a hack; can we convert these instructions to set the
- // "codegen only" bit instead?
- if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
- if (Form->getValue()->getAsString() == "Pseudo")
- return false;
-
- // Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
- //
- // FIXME: This is a total hack.
- if (StringRef(Name).startswith("Int_") || StringRef(Name).endswith("_Int"))
- return false;
-
- // Ignore instructions with no .s string.
- //
- // FIXME: What are these?
- if (CGI.AsmString.empty())
- return false;
-
- // FIXME: Hack; ignore any instructions with a newline in them.
- if (std::find(CGI.AsmString.begin(),
- CGI.AsmString.end(), '\n') != CGI.AsmString.end())
- return false;
-
- // Ignore instructions with attributes, these are always fake instructions for
- // simplifying codegen.
- //
- // FIXME: Is this true?
- //
- // Also, check for instructions which reference the operand multiple times;
- // this implies a constraint we would not honor.
- std::set<std::string> OperandNames;
- for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
- if (Tokens[i][0] == '$' &&
- std::find(Tokens[i].begin(),
- Tokens[i].end(), ':') != Tokens[i].end()) {
- DEBUG({
- errs() << "warning: '" << Name << "': "
- << "ignoring instruction; operand with attribute '"
- << Tokens[i] << "'\n";
- });
- return false;
- }
-
- if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second) {
- DEBUG({
- errs() << "warning: '" << Name << "': "
- << "ignoring instruction with tied operand '"
- << Tokens[i].str() << "'\n";
- });
- return false;
- }
- }
-
- return true;
-}
-
namespace {
-
+class AsmMatcherInfo;
struct SubtargetFeatureInfo;
/// ClassInfo - Helper class for storing the information about a particular
@@ -331,6 +167,10 @@ struct ClassInfo {
/// MCInst; this is not valid for Token or register kinds.
std::string RenderMethod;
+ /// ParserMethod - The name of the operand method to do a target specific
+ /// parsing on the operand.
+ std::string ParserMethod;
+
/// For register classes, the records for all the registers in this class.
std::set<Record*> Registers;
@@ -360,7 +200,7 @@ public:
std::set<Record*> Tmp;
std::insert_iterator< std::set<Record*> > II(Tmp, Tmp.begin());
- std::set_intersection(Registers.begin(), Registers.end(),
+ std::set_intersection(Registers.begin(), Registers.end(),
RHS.Registers.begin(), RHS.Registers.end(),
II);
@@ -380,11 +220,11 @@ public:
const ClassInfo *RHSRoot = &RHS;
while (!RHSRoot->SuperClasses.empty())
RHSRoot = RHSRoot->SuperClasses.front();
-
+
return Root == RHSRoot;
}
- /// isSubsetOf - Test whether this class is a subset of \arg RHS;
+ /// isSubsetOf - Test whether this class is a subset of \arg RHS;
bool isSubsetOf(const ClassInfo &RHS) const {
// This is a subset of RHS if it is the same class...
if (this == &RHS)
@@ -430,32 +270,131 @@ public:
}
};
-/// InstructionInfo - Helper class for storing the necessary information for an
-/// instruction which is capable of being matched.
-struct InstructionInfo {
- struct Operand {
+/// MatchableInfo - Helper class for storing the necessary information for an
+/// instruction or alias which is capable of being matched.
+struct MatchableInfo {
+ struct AsmOperand {
+ /// Token - This is the token that the operand came from.
+ StringRef Token;
+
/// The unique class instance this operand should match.
ClassInfo *Class;
- /// The original operand this corresponds to, if any.
- const CodeGenInstruction::OperandInfo *OperandInfo;
+ /// The operand name this is, if anything.
+ StringRef SrcOpName;
+
+ /// The suboperand index within SrcOpName, or -1 for the entire operand.
+ int SubOpIdx;
+
+ explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1) {}
};
- /// InstrName - The target name for this instruction.
- std::string InstrName;
+ /// ResOperand - This represents a single operand in the result instruction
+ /// generated by the match. In cases (like addressing modes) where a single
+ /// assembler operand expands to multiple MCOperands, this represents the
+ /// single assembler operand, not the MCOperand.
+ struct ResOperand {
+ enum {
+ /// RenderAsmOperand - This represents an operand result that is
+ /// generated by calling the render method on the assembly operand. The
+ /// corresponding AsmOperand is specified by AsmOperandNum.
+ RenderAsmOperand,
+
+ /// TiedOperand - This represents a result operand that is a duplicate of
+ /// a previous result operand.
+ TiedOperand,
+
+ /// ImmOperand - This represents an immediate value that is dumped into
+ /// the operand.
+ ImmOperand,
+
+ /// RegOperand - This represents a fixed register that is dumped in.
+ RegOperand
+ } Kind;
+
+ union {
+ /// This is the operand # in the AsmOperands list that this should be
+ /// copied from.
+ unsigned AsmOperandNum;
+
+ /// TiedOperandNum - This is the (earlier) result operand that should be
+ /// copied from.
+ unsigned TiedOperandNum;
+
+ /// ImmVal - This is the immediate value added to the instruction.
+ int64_t ImmVal;
+
+ /// Register - This is the register record.
+ Record *Register;
+ };
+
+ /// MINumOperands - The number of MCInst operands populated by this
+ /// operand.
+ unsigned MINumOperands;
+
+ static ResOperand getRenderedOp(unsigned AsmOpNum, unsigned NumOperands) {
+ ResOperand X;
+ X.Kind = RenderAsmOperand;
+ X.AsmOperandNum = AsmOpNum;
+ X.MINumOperands = NumOperands;
+ return X;
+ }
+
+ static ResOperand getTiedOp(unsigned TiedOperandNum) {
+ ResOperand X;
+ X.Kind = TiedOperand;
+ X.TiedOperandNum = TiedOperandNum;
+ X.MINumOperands = 1;
+ return X;
+ }
- /// Instr - The instruction this matches.
- const CodeGenInstruction *Instr;
+ static ResOperand getImmOp(int64_t Val) {
+ ResOperand X;
+ X.Kind = ImmOperand;
+ X.ImmVal = Val;
+ X.MINumOperands = 1;
+ return X;
+ }
+
+ static ResOperand getRegOp(Record *Reg) {
+ ResOperand X;
+ X.Kind = RegOperand;
+ X.Register = Reg;
+ X.MINumOperands = 1;
+ return X;
+ }
+ };
+
+ /// TheDef - This is the definition of the instruction or InstAlias that this
+ /// matchable came from.
+ Record *const TheDef;
+
+ /// DefRec - This is the definition that it came from.
+ PointerUnion<const CodeGenInstruction*, const CodeGenInstAlias*> DefRec;
+
+ const CodeGenInstruction *getResultInst() const {
+ if (DefRec.is<const CodeGenInstruction*>())
+ return DefRec.get<const CodeGenInstruction*>();
+ return DefRec.get<const CodeGenInstAlias*>()->ResultInst;
+ }
+
+ /// ResOperands - This is the operand list that should be built for the result
+ /// MCInst.
+ std::vector<ResOperand> ResOperands;
/// AsmString - The assembly string for this instruction (with variants
- /// removed).
+ /// removed), e.g. "movsx $src, $dst".
std::string AsmString;
- /// Tokens - The tokenized assembly pattern that this instruction matches.
- SmallVector<StringRef, 4> Tokens;
+ /// Mnemonic - This is the first token of the matched instruction, its
+ /// mnemonic.
+ StringRef Mnemonic;
- /// Operands - The operands that this instruction matches.
- SmallVector<Operand, 4> Operands;
+ /// AsmOperands - The textual operands that this instruction matches,
+ /// annotated with a class and where in the OperandList they were defined.
+ /// This directly corresponds to the tokenized AsmString after the mnemonic is
+ /// removed.
+ SmallVector<AsmOperand, 4> AsmOperands;
/// Predicates - The required subtarget features to match this instruction.
SmallVector<SubtargetFeatureInfo*, 4> RequiredFeatures;
@@ -465,29 +404,79 @@ struct InstructionInfo {
/// function.
std::string ConversionFnKind;
- /// operator< - Compare two instructions.
- bool operator<(const InstructionInfo &RHS) const {
- if (Operands.size() != RHS.Operands.size())
- return Operands.size() < RHS.Operands.size();
+ MatchableInfo(const CodeGenInstruction &CGI)
+ : TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) {
+ }
+
+ MatchableInfo(const CodeGenInstAlias *Alias)
+ : TheDef(Alias->TheDef), DefRec(Alias), AsmString(Alias->AsmString) {
+ }
+
+ void Initialize(const AsmMatcherInfo &Info,
+ SmallPtrSet<Record*, 16> &SingletonRegisters);
+
+ /// Validate - Return true if this matchable is a valid thing to match against
+ /// and perform a bunch of validity checking.
+ bool Validate(StringRef CommentDelimiter, bool Hack) const;
+
+ /// getSingletonRegisterForAsmOperand - If the specified token is a singleton
+ /// register, return the Record for it, otherwise return null.
+ Record *getSingletonRegisterForAsmOperand(unsigned i,
+ const AsmMatcherInfo &Info) const;
+
+ /// FindAsmOperand - Find the AsmOperand with the specified name and
+ /// suboperand index.
+ int FindAsmOperand(StringRef N, int SubOpIdx) const {
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
+ if (N == AsmOperands[i].SrcOpName &&
+ SubOpIdx == AsmOperands[i].SubOpIdx)
+ return i;
+ return -1;
+ }
+
+ /// FindAsmOperandNamed - Find the first AsmOperand with the specified name.
+ /// This does not check the suboperand index.
+ int FindAsmOperandNamed(StringRef N) const {
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
+ if (N == AsmOperands[i].SrcOpName)
+ return i;
+ return -1;
+ }
+
+ void BuildInstructionResultOperands();
+ void BuildAliasResultOperands();
+
+ /// operator< - Compare two matchables.
+ bool operator<(const MatchableInfo &RHS) const {
+ // The primary comparator is the instruction mnemonic.
+ if (Mnemonic != RHS.Mnemonic)
+ return Mnemonic < RHS.Mnemonic;
+
+ if (AsmOperands.size() != RHS.AsmOperands.size())
+ return AsmOperands.size() < RHS.AsmOperands.size();
// Compare lexicographically by operand. The matcher validates that other
- // orderings wouldn't be ambiguous using \see CouldMatchAmiguouslyWith().
- for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- if (*Operands[i].Class < *RHS.Operands[i].Class)
+ // orderings wouldn't be ambiguous using \see CouldMatchAmbiguouslyWith().
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
+ if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class)
return true;
- if (*RHS.Operands[i].Class < *Operands[i].Class)
+ if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class)
return false;
}
return false;
}
- /// CouldMatchAmiguouslyWith - Check whether this instruction could
+ /// CouldMatchAmbiguouslyWith - Check whether this matchable could
/// ambiguously match the same set of operands as \arg RHS (without being a
/// strictly superior match).
- bool CouldMatchAmiguouslyWith(const InstructionInfo &RHS) {
+ bool CouldMatchAmbiguouslyWith(const MatchableInfo &RHS) {
+ // The primary comparator is the instruction mnemonic.
+ if (Mnemonic != RHS.Mnemonic)
+ return false;
+
// The number of operands is unambiguous.
- if (Operands.size() != RHS.Operands.size())
+ if (AsmOperands.size() != RHS.AsmOperands.size())
return false;
// Otherwise, make sure the ordering of the two instructions is unambiguous
@@ -496,29 +485,31 @@ struct InstructionInfo {
// Tokens and operand kinds are unambiguous (assuming a correct target
// specific parser).
- for (unsigned i = 0, e = Operands.size(); i != e; ++i)
- if (Operands[i].Class->Kind != RHS.Operands[i].Class->Kind ||
- Operands[i].Class->Kind == ClassInfo::Token)
- if (*Operands[i].Class < *RHS.Operands[i].Class ||
- *RHS.Operands[i].Class < *Operands[i].Class)
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
+ if (AsmOperands[i].Class->Kind != RHS.AsmOperands[i].Class->Kind ||
+ AsmOperands[i].Class->Kind == ClassInfo::Token)
+ if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class ||
+ *RHS.AsmOperands[i].Class < *AsmOperands[i].Class)
return false;
-
+
// Otherwise, this operand could commute if all operands are equivalent, or
// there is a pair of operands that compare less than and a pair that
// compare greater than.
bool HasLT = false, HasGT = false;
- for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- if (*Operands[i].Class < *RHS.Operands[i].Class)
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
+ if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class)
HasLT = true;
- if (*RHS.Operands[i].Class < *Operands[i].Class)
+ if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class)
HasGT = true;
}
return !(HasLT ^ HasGT);
}
-public:
void dump();
+
+private:
+ void TokenizeAsmString(const AsmMatcherInfo &Info);
};
/// SubtargetFeatureInfo - Helper class for storing information on a subtarget
@@ -530,26 +521,52 @@ struct SubtargetFeatureInfo {
/// \brief An unique index assigned to represent this feature.
unsigned Index;
+ SubtargetFeatureInfo(Record *D, unsigned Idx) : TheDef(D), Index(Idx) {}
+
/// \brief The name of the enumerated constant identifying this feature.
- std::string EnumName;
+ std::string getEnumName() const {
+ return "Feature_" + TheDef->getName();
+ }
};
+struct OperandMatchEntry {
+ unsigned OperandMask;
+ MatchableInfo* MI;
+ ClassInfo *CI;
+
+ static OperandMatchEntry Create(MatchableInfo* mi, ClassInfo *ci,
+ unsigned opMask) {
+ OperandMatchEntry X;
+ X.OperandMask = opMask;
+ X.CI = ci;
+ X.MI = mi;
+ return X;
+ }
+};
+
+
class AsmMatcherInfo {
public:
+ /// Tracked Records
+ RecordKeeper &Records;
+
/// The tablegen AsmParser record.
Record *AsmParser;
- /// The AsmParser "CommentDelimiter" value.
- std::string CommentDelimiter;
+ /// Target - The target information.
+ CodeGenTarget &Target;
/// The AsmParser "RegisterPrefix" value.
std::string RegisterPrefix;
/// The classes which are needed for matching.
std::vector<ClassInfo*> Classes;
-
- /// The information on the instruction to match.
- std::vector<InstructionInfo*> Instructions;
+
+ /// The information on the matchables to match.
+ std::vector<MatchableInfo*> Matchables;
+
+ /// Info for custom matching operands by user defined methods.
+ std::vector<OperandMatchEntry> OperandMatchInfo;
/// Map of Register records to their class information.
std::map<Record*, ClassInfo*> RegisterClasses;
@@ -572,108 +589,265 @@ private:
ClassInfo *getTokenClass(StringRef Token);
/// getOperandClass - Lookup or create the class for the given operand.
- ClassInfo *getOperandClass(StringRef Token,
- const CodeGenInstruction::OperandInfo &OI);
-
- /// getSubtargetFeature - Lookup or create the subtarget feature info for the
- /// given operand.
- SubtargetFeatureInfo *getSubtargetFeature(Record *Def) {
- assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!");
-
- SubtargetFeatureInfo *&Entry = SubtargetFeatures[Def];
- if (!Entry) {
- Entry = new SubtargetFeatureInfo;
- Entry->TheDef = Def;
- Entry->Index = SubtargetFeatures.size() - 1;
- Entry->EnumName = "Feature_" + Def->getName();
- assert(Entry->Index < 32 && "Too many subtarget features!");
- }
-
- return Entry;
- }
+ ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI,
+ int SubOpIdx = -1);
/// BuildRegisterClasses - Build the ClassInfo* instances for register
/// classes.
- void BuildRegisterClasses(CodeGenTarget &Target,
- std::set<std::string> &SingletonRegisterNames);
+ void BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters);
/// BuildOperandClasses - Build the ClassInfo* instances for user defined
/// operand classes.
- void BuildOperandClasses(CodeGenTarget &Target);
+ void BuildOperandClasses();
+
+ void BuildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
+ unsigned AsmOpIdx);
+ void BuildAliasOperandReference(MatchableInfo *II, StringRef OpName,
+ MatchableInfo::AsmOperand &Op);
public:
- AsmMatcherInfo(Record *_AsmParser);
+ AsmMatcherInfo(Record *AsmParser,
+ CodeGenTarget &Target,
+ RecordKeeper &Records);
/// BuildInfo - Construct the various tables used during matching.
- void BuildInfo(CodeGenTarget &Target);
+ void BuildInfo();
+
+ /// BuildOperandMatchInfo - Build the necessary information to handle user
+ /// defined operand parsing methods.
+ void BuildOperandMatchInfo();
+
+ /// getSubtargetFeature - Lookup or create the subtarget feature info for the
+ /// given operand.
+ SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const {
+ assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!");
+ std::map<Record*, SubtargetFeatureInfo*>::const_iterator I =
+ SubtargetFeatures.find(Def);
+ return I == SubtargetFeatures.end() ? 0 : I->second;
+ }
+
+ RecordKeeper &getRecords() const {
+ return Records;
+ }
};
}
-void InstructionInfo::dump() {
- errs() << InstrName << " -- " << "flattened:\"" << AsmString << '\"'
- << ", tokens:[";
- for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
- errs() << Tokens[i];
- if (i + 1 != e)
- errs() << ", ";
- }
- errs() << "]\n";
+void MatchableInfo::dump() {
+ errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n";
- for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- Operand &Op = Operands[i];
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
+ AsmOperand &Op = AsmOperands[i];
errs() << " op[" << i << "] = " << Op.Class->ClassName << " - ";
- if (Op.Class->Kind == ClassInfo::Token) {
- errs() << '\"' << Tokens[i] << "\"\n";
- continue;
+ errs() << '\"' << Op.Token << "\"\n";
+ }
+}
+
+void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
+ SmallPtrSet<Record*, 16> &SingletonRegisters) {
+ // TODO: Eventually support asmparser for Variant != 0.
+ AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, 0);
+
+ TokenizeAsmString(Info);
+
+ // Compute the require features.
+ std::vector<Record*> Predicates =TheDef->getValueAsListOfDefs("Predicates");
+ for (unsigned i = 0, e = Predicates.size(); i != e; ++i)
+ if (SubtargetFeatureInfo *Feature =
+ Info.getSubtargetFeature(Predicates[i]))
+ RequiredFeatures.push_back(Feature);
+
+ // Collect singleton registers, if used.
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
+ if (Record *Reg = getSingletonRegisterForAsmOperand(i, Info))
+ SingletonRegisters.insert(Reg);
+ }
+}
+
+/// TokenizeAsmString - Tokenize a simplified assembly string.
+void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
+ StringRef String = AsmString;
+ unsigned Prev = 0;
+ bool InTok = true;
+ for (unsigned i = 0, e = String.size(); i != e; ++i) {
+ switch (String[i]) {
+ case '[':
+ case ']':
+ case '*':
+ case '!':
+ case ' ':
+ case '\t':
+ case ',':
+ if (InTok) {
+ AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
+ InTok = false;
+ }
+ if (!isspace(String[i]) && String[i] != ',')
+ AsmOperands.push_back(AsmOperand(String.substr(i, 1)));
+ Prev = i + 1;
+ break;
+
+ case '\\':
+ if (InTok) {
+ AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
+ InTok = false;
+ }
+ ++i;
+ assert(i != String.size() && "Invalid quoted character");
+ AsmOperands.push_back(AsmOperand(String.substr(i, 1)));
+ Prev = i + 1;
+ break;
+
+ case '$': {
+ if (InTok) {
+ AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
+ InTok = false;
+ }
+
+ // If this isn't "${", treat like a normal token.
+ if (i + 1 == String.size() || String[i + 1] != '{') {
+ Prev = i;
+ break;
+ }
+
+ StringRef::iterator End = std::find(String.begin() + i, String.end(),'}');
+ assert(End != String.end() && "Missing brace in operand reference!");
+ size_t EndPos = End - String.begin();
+ AsmOperands.push_back(AsmOperand(String.slice(i, EndPos+1)));
+ Prev = EndPos + 1;
+ i = EndPos;
+ break;
}
- if (!Op.OperandInfo) {
- errs() << "(singleton register)\n";
- continue;
+ case '.':
+ if (InTok)
+ AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
+ Prev = i;
+ InTok = true;
+ break;
+
+ default:
+ InTok = true;
}
+ }
+ if (InTok && Prev != String.size())
+ AsmOperands.push_back(AsmOperand(String.substr(Prev)));
+
+ // The first token of the instruction is the mnemonic, which must be a
+ // simple string, not a $foo variable or a singleton register.
+ assert(!AsmOperands.empty() && "Instruction has no tokens?");
+ Mnemonic = AsmOperands[0].Token;
+ if (Mnemonic[0] == '$' || getSingletonRegisterForAsmOperand(0, Info))
+ throw TGError(TheDef->getLoc(),
+ "Invalid instruction mnemonic '" + Mnemonic.str() + "'!");
+
+ // Remove the first operand, it is tracked in the mnemonic field.
+ AsmOperands.erase(AsmOperands.begin());
+}
- const CodeGenInstruction::OperandInfo &OI = *Op.OperandInfo;
- errs() << OI.Name << " " << OI.Rec->getName()
- << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
+bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
+ // Reject matchables with no .s string.
+ if (AsmString.empty())
+ throw TGError(TheDef->getLoc(), "instruction with empty asm string");
+
+ // Reject any matchables with a newline in them, they should be marked
+ // isCodeGenOnly if they are pseudo instructions.
+ if (AsmString.find('\n') != std::string::npos)
+ throw TGError(TheDef->getLoc(),
+ "multiline instruction is not valid for the asmparser, "
+ "mark it isCodeGenOnly");
+
+ // Remove comments from the asm string. We know that the asmstring only
+ // has one line.
+ if (!CommentDelimiter.empty() &&
+ StringRef(AsmString).find(CommentDelimiter) != StringRef::npos)
+ throw TGError(TheDef->getLoc(),
+ "asmstring for instruction has comment character in it, "
+ "mark it isCodeGenOnly");
+
+ // Reject matchables with operand modifiers, these aren't something we can
+ // handle, the target should be refactored to use operands instead of
+ // modifiers.
+ //
+ // Also, check for instructions which reference the operand multiple times;
+ // this implies a constraint we would not honor.
+ std::set<std::string> OperandNames;
+ for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
+ StringRef Tok = AsmOperands[i].Token;
+ if (Tok[0] == '$' && Tok.find(':') != StringRef::npos)
+ throw TGError(TheDef->getLoc(),
+ "matchable with operand modifier '" + Tok.str() +
+ "' not supported by asm matcher. Mark isCodeGenOnly!");
+
+ // Verify that any operand is only mentioned once.
+ // We reject aliases and ignore instructions for now.
+ if (Tok[0] == '$' && !OperandNames.insert(Tok).second) {
+ if (!Hack)
+ throw TGError(TheDef->getLoc(),
+ "ERROR: matchable with tied operand '" + Tok.str() +
+ "' can never be matched!");
+ // FIXME: Should reject these. The ARM backend hits this with $lane in a
+ // bunch of instructions. It is unclear what the right answer is.
+ DEBUG({
+ errs() << "warning: '" << TheDef->getName() << "': "
+ << "ignoring instruction with tied operand '"
+ << Tok.str() << "'\n";
+ });
+ return false;
+ }
}
+
+ return true;
+}
+
+/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
+/// register, return the register name, otherwise return a null StringRef.
+Record *MatchableInfo::
+getSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info) const{
+ StringRef Tok = AsmOperands[i].Token;
+ if (!Tok.startswith(Info.RegisterPrefix))
+ return 0;
+
+ StringRef RegName = Tok.substr(Info.RegisterPrefix.size());
+ if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(RegName))
+ return Reg->TheDef;
+
+ // If there is no register prefix (i.e. "%" in "%eax"), then this may
+ // be some random non-register token, just ignore it.
+ if (Info.RegisterPrefix.empty())
+ return 0;
+
+ // Otherwise, we have something invalid prefixed with the register prefix,
+ // such as %foo.
+ std::string Err = "unable to find register for '" + RegName.str() +
+ "' (which matches register prefix)";
+ throw TGError(TheDef->getLoc(), Err);
}
static std::string getEnumNameForToken(StringRef Str) {
std::string Res;
-
+
for (StringRef::iterator it = Str.begin(), ie = Str.end(); it != ie; ++it) {
switch (*it) {
case '*': Res += "_STAR_"; break;
case '%': Res += "_PCT_"; break;
case ':': Res += "_COLON_"; break;
-
+ case '!': Res += "_EXCLAIM_"; break;
+ case '.': Res += "_DOT_"; break;
default:
- if (isalnum(*it)) {
+ if (isalnum(*it))
Res += *it;
- } else {
+ else
Res += "_" + utostr((unsigned) *it) + "_";
- }
}
}
return Res;
}
-/// getRegisterRecord - Get the register record for \arg name, or 0.
-static Record *getRegisterRecord(CodeGenTarget &Target, StringRef Name) {
- for (unsigned i = 0, e = Target.getRegisters().size(); i != e; ++i) {
- const CodeGenRegister &Reg = Target.getRegisters()[i];
- if (Name == Reg.TheDef->getValueAsString("AsmName"))
- return Reg.TheDef;
- }
-
- return 0;
-}
-
ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
ClassInfo *&Entry = TokenClasses[Token];
-
+
if (!Entry) {
Entry = new ClassInfo();
Entry->Kind = ClassInfo::Token;
@@ -682,6 +856,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
Entry->ValueName = Token;
Entry->PredicateMethod = "<invalid>";
Entry->RenderMethod = "<invalid>";
+ Entry->ParserMethod = "";
Classes.push_back(Entry);
}
@@ -689,65 +864,58 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
}
ClassInfo *
-AsmMatcherInfo::getOperandClass(StringRef Token,
- const CodeGenInstruction::OperandInfo &OI) {
- if (OI.Rec->isSubClassOf("RegisterClass")) {
- ClassInfo *CI = RegisterClassClasses[OI.Rec];
-
- if (!CI) {
- PrintError(OI.Rec->getLoc(), "register class has no class info!");
- throw std::string("ERROR: Missing register class!");
- }
-
- return CI;
+AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI,
+ int SubOpIdx) {
+ Record *Rec = OI.Rec;
+ if (SubOpIdx != -1)
+ Rec = dynamic_cast<DefInit*>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef();
+
+ if (Rec->isSubClassOf("RegisterClass")) {
+ if (ClassInfo *CI = RegisterClassClasses[Rec])
+ return CI;
+ throw TGError(Rec->getLoc(), "register class has no class info!");
}
- assert(OI.Rec->isSubClassOf("Operand") && "Unexpected operand!");
- Record *MatchClass = OI.Rec->getValueAsDef("ParserMatchClass");
- ClassInfo *CI = AsmOperandClasses[MatchClass];
-
- if (!CI) {
- PrintError(OI.Rec->getLoc(), "operand has no match class!");
- throw std::string("ERROR: Missing match class!");
- }
+ assert(Rec->isSubClassOf("Operand") && "Unexpected operand!");
+ Record *MatchClass = Rec->getValueAsDef("ParserMatchClass");
+ if (ClassInfo *CI = AsmOperandClasses[MatchClass])
+ return CI;
- return CI;
+ throw TGError(Rec->getLoc(), "operand has no match class!");
}
-void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target,
- std::set<std::string>
- &SingletonRegisterNames) {
- std::vector<CodeGenRegisterClass> RegisterClasses;
- std::vector<CodeGenRegister> Registers;
-
- RegisterClasses = Target.getRegisterClasses();
- Registers = Target.getRegisters();
+void AsmMatcherInfo::
+BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
+ const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
+ const std::vector<CodeGenRegisterClass> &RegClassList =
+ Target.getRegisterClasses();
// The register sets used for matching.
std::set< std::set<Record*> > RegisterSets;
- // Gather the defined sets.
- for (std::vector<CodeGenRegisterClass>::iterator it = RegisterClasses.begin(),
- ie = RegisterClasses.end(); it != ie; ++it)
+ // Gather the defined sets.
+ for (std::vector<CodeGenRegisterClass>::const_iterator it =
+ RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it)
RegisterSets.insert(std::set<Record*>(it->Elements.begin(),
it->Elements.end()));
// Add any required singleton sets.
- for (std::set<std::string>::iterator it = SingletonRegisterNames.begin(),
- ie = SingletonRegisterNames.end(); it != ie; ++it)
- if (Record *Rec = getRegisterRecord(Target, *it))
- RegisterSets.insert(std::set<Record*>(&Rec, &Rec + 1));
-
+ for (SmallPtrSet<Record*, 16>::iterator it = SingletonRegisters.begin(),
+ ie = SingletonRegisters.end(); it != ie; ++it) {
+ Record *Rec = *it;
+ RegisterSets.insert(std::set<Record*>(&Rec, &Rec + 1));
+ }
+
// Introduce derived sets where necessary (when a register does not determine
// a unique register set class), and build the mapping of registers to the set
// they should classify to.
std::map<Record*, std::set<Record*> > RegisterMap;
- for (std::vector<CodeGenRegister>::iterator it = Registers.begin(),
+ for (std::vector<CodeGenRegister>::const_iterator it = Registers.begin(),
ie = Registers.end(); it != ie; ++it) {
- CodeGenRegister &CGR = *it;
+ const CodeGenRegister &CGR = *it;
// Compute the intersection of all sets containing this register.
std::set<Record*> ContainingSet;
-
+
for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(),
ie = RegisterSets.end(); it != ie; ++it) {
if (!it->count(CGR.TheDef))
@@ -755,14 +923,14 @@ void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target,
if (ContainingSet.empty()) {
ContainingSet = *it;
- } else {
- std::set<Record*> Tmp;
- std::swap(Tmp, ContainingSet);
- std::insert_iterator< std::set<Record*> > II(ContainingSet,
- ContainingSet.begin());
- std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(),
- II);
+ continue;
}
+
+ std::set<Record*> Tmp;
+ std::swap(Tmp, ContainingSet);
+ std::insert_iterator< std::set<Record*> > II(ContainingSet,
+ ContainingSet.begin());
+ std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II);
}
if (!ContainingSet.empty()) {
@@ -795,14 +963,14 @@ void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target,
ClassInfo *CI = RegisterSetClasses[*it];
for (std::set< std::set<Record*> >::iterator it2 = RegisterSets.begin(),
ie2 = RegisterSets.end(); it2 != ie2; ++it2)
- if (*it != *it2 &&
+ if (*it != *it2 &&
std::includes(it2->begin(), it2->end(), it->begin(), it->end()))
CI->SuperClasses.push_back(RegisterSetClasses[*it2]);
}
// Name the register classes which correspond to a user defined RegisterClass.
- for (std::vector<CodeGenRegisterClass>::iterator it = RegisterClasses.begin(),
- ie = RegisterClasses.end(); it != ie; ++it) {
+ for (std::vector<CodeGenRegisterClass>::const_iterator
+ it = RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) {
ClassInfo *CI = RegisterSetClasses[std::set<Record*>(it->Elements.begin(),
it->Elements.end())];
if (CI->ValueName.empty()) {
@@ -818,36 +986,35 @@ void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target,
// Populate the map for individual registers.
for (std::map<Record*, std::set<Record*> >::iterator it = RegisterMap.begin(),
ie = RegisterMap.end(); it != ie; ++it)
- this->RegisterClasses[it->first] = RegisterSetClasses[it->second];
+ RegisterClasses[it->first] = RegisterSetClasses[it->second];
// Name the register classes which correspond to singleton registers.
- for (std::set<std::string>::iterator it = SingletonRegisterNames.begin(),
- ie = SingletonRegisterNames.end(); it != ie; ++it) {
- if (Record *Rec = getRegisterRecord(Target, *it)) {
- ClassInfo *CI = this->RegisterClasses[Rec];
- assert(CI && "Missing singleton register class info!");
-
- if (CI->ValueName.empty()) {
- CI->ClassName = Rec->getName();
- CI->Name = "MCK_" + Rec->getName();
- CI->ValueName = Rec->getName();
- } else
- CI->ValueName = CI->ValueName + "," + Rec->getName();
- }
+ for (SmallPtrSet<Record*, 16>::iterator it = SingletonRegisters.begin(),
+ ie = SingletonRegisters.end(); it != ie; ++it) {
+ Record *Rec = *it;
+ ClassInfo *CI = RegisterClasses[Rec];
+ assert(CI && "Missing singleton register class info!");
+
+ if (CI->ValueName.empty()) {
+ CI->ClassName = Rec->getName();
+ CI->Name = "MCK_" + Rec->getName();
+ CI->ValueName = Rec->getName();
+ } else
+ CI->ValueName = CI->ValueName + "," + Rec->getName();
}
}
-void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) {
- std::vector<Record*> AsmOperands;
- AsmOperands = Records.getAllDerivedDefinitions("AsmOperandClass");
+void AsmMatcherInfo::BuildOperandClasses() {
+ std::vector<Record*> AsmOperands =
+ Records.getAllDerivedDefinitions("AsmOperandClass");
// Pre-populate AsmOperandClasses map.
- for (std::vector<Record*>::iterator it = AsmOperands.begin(),
+ for (std::vector<Record*>::iterator it = AsmOperands.begin(),
ie = AsmOperands.end(); it != ie; ++it)
AsmOperandClasses[*it] = new ClassInfo();
unsigned Index = 0;
- for (std::vector<Record*>::iterator it = AsmOperands.begin(),
+ for (std::vector<Record*>::iterator it = AsmOperands.begin(),
ie = AsmOperands.end(); it != ie; ++it, ++Index) {
ClassInfo *CI = AsmOperandClasses[*it];
CI->Kind = ClassInfo::UserClass0 + Index;
@@ -875,7 +1042,7 @@ void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) {
if (StringInit *SI = dynamic_cast<StringInit*>(PMName)) {
CI->PredicateMethod = SI->getValue();
} else {
- assert(dynamic_cast<UnsetInit*>(PMName) &&
+ assert(dynamic_cast<UnsetInit*>(PMName) &&
"Unexpected PredicateMethod field!");
CI->PredicateMethod = "is" + CI->ClassName;
}
@@ -890,128 +1057,192 @@ void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) {
CI->RenderMethod = "add" + CI->ClassName + "Operands";
}
+ // Get the parse method name or leave it as empty.
+ Init *PRMName = (*it)->getValueInit("ParserMethod");
+ if (StringInit *SI = dynamic_cast<StringInit*>(PRMName))
+ CI->ParserMethod = SI->getValue();
+
AsmOperandClasses[*it] = CI;
Classes.push_back(CI);
}
}
-AsmMatcherInfo::AsmMatcherInfo(Record *_AsmParser)
- : AsmParser(_AsmParser),
- CommentDelimiter(AsmParser->getValueAsString("CommentDelimiter")),
- RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix"))
-{
+AsmMatcherInfo::AsmMatcherInfo(Record *asmParser,
+ CodeGenTarget &target,
+ RecordKeeper &records)
+ : Records(records), AsmParser(asmParser), Target(target),
+ RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) {
+}
+
+/// BuildOperandMatchInfo - Build the necessary information to handle user
+/// defined operand parsing methods.
+void AsmMatcherInfo::BuildOperandMatchInfo() {
+
+ /// Map containing a mask with all operands indicies that can be found for
+ /// that class inside a instruction.
+ std::map<ClassInfo*, unsigned> OpClassMask;
+
+ for (std::vector<MatchableInfo*>::const_iterator it =
+ Matchables.begin(), ie = Matchables.end();
+ it != ie; ++it) {
+ MatchableInfo &II = **it;
+ OpClassMask.clear();
+
+ // Keep track of all operands of this instructions which belong to the
+ // same class.
+ for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
+ MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
+ if (Op.Class->ParserMethod.empty())
+ continue;
+ unsigned &OperandMask = OpClassMask[Op.Class];
+ OperandMask |= (1 << i);
+ }
+
+ // Generate operand match info for each mnemonic/operand class pair.
+ for (std::map<ClassInfo*, unsigned>::iterator iit = OpClassMask.begin(),
+ iie = OpClassMask.end(); iit != iie; ++iit) {
+ unsigned OpMask = iit->second;
+ ClassInfo *CI = iit->first;
+ OperandMatchInfo.push_back(OperandMatchEntry::Create(&II, CI, OpMask));
+ }
+ }
}
-void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
+void AsmMatcherInfo::BuildInfo() {
+ // Build information about all of the AssemblerPredicates.
+ std::vector<Record*> AllPredicates =
+ Records.getAllDerivedDefinitions("Predicate");
+ for (unsigned i = 0, e = AllPredicates.size(); i != e; ++i) {
+ Record *Pred = AllPredicates[i];
+ // Ignore predicates that are not intended for the assembler.
+ if (!Pred->getValueAsBit("AssemblerMatcherPredicate"))
+ continue;
+
+ if (Pred->getName().empty())
+ throw TGError(Pred->getLoc(), "Predicate has no name!");
+
+ unsigned FeatureNo = SubtargetFeatures.size();
+ SubtargetFeatures[Pred] = new SubtargetFeatureInfo(Pred, FeatureNo);
+ assert(FeatureNo < 32 && "Too many subtarget features!");
+ }
+
+ StringRef CommentDelimiter = AsmParser->getValueAsString("CommentDelimiter");
+
// Parse the instructions; we need to do this first so that we can gather the
// singleton register classes.
- std::set<std::string> SingletonRegisterNames;
-
- const std::vector<const CodeGenInstruction*> &InstrList =
- Target.getInstructionsByEnumValue();
-
- for (unsigned i = 0, e = InstrList.size(); i != e; ++i) {
- const CodeGenInstruction &CGI = *InstrList[i];
+ SmallPtrSet<Record*, 16> SingletonRegisters;
+ for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
+ E = Target.inst_end(); I != E; ++I) {
+ const CodeGenInstruction &CGI = **I;
+ // If the tblgen -match-prefix option is specified (for tblgen hackers),
+ // filter the set of instructions we consider.
if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix))
continue;
- OwningPtr<InstructionInfo> II(new InstructionInfo());
-
- II->InstrName = CGI.TheDef->getName();
- II->Instr = &CGI;
- II->AsmString = FlattenVariants(CGI.AsmString, 0);
-
- // Remove comments from the asm string.
- if (!CommentDelimiter.empty()) {
- size_t Idx = StringRef(II->AsmString).find(CommentDelimiter);
- if (Idx != StringRef::npos)
- II->AsmString = II->AsmString.substr(0, Idx);
- }
-
- TokenizeAsmString(II->AsmString, II->Tokens);
-
- // Ignore instructions which shouldn't be matched.
- if (!IsAssemblerInstruction(CGI.TheDef->getName(), CGI, II->Tokens))
+ // Ignore "codegen only" instructions.
+ if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
continue;
- // Collect singleton registers, if used.
- if (!RegisterPrefix.empty()) {
- for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) {
- if (II->Tokens[i].startswith(RegisterPrefix)) {
- StringRef RegName = II->Tokens[i].substr(RegisterPrefix.size());
- Record *Rec = getRegisterRecord(Target, RegName);
-
- if (!Rec) {
- std::string Err = "unable to find register for '" + RegName.str() +
- "' (which matches register prefix)";
- throw TGError(CGI.TheDef->getLoc(), Err);
- }
-
- SingletonRegisterNames.insert(RegName);
+ // Validate the operand list to ensure we can handle this instruction.
+ for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
+ const CGIOperandList::OperandInfo &OI = CGI.Operands[i];
+
+ // Validate tied operands.
+ if (OI.getTiedRegister() != -1) {
+ // If we have a tied operand that consists of multiple MCOperands,
+ // reject it. We reject aliases and ignore instructions for now.
+ if (OI.MINumOperands != 1) {
+ // FIXME: Should reject these. The ARM backend hits this with $lane
+ // in a bunch of instructions. It is unclear what the right answer is.
+ DEBUG({
+ errs() << "warning: '" << CGI.TheDef->getName() << "': "
+ << "ignoring instruction with multi-operand tied operand '"
+ << OI.Name << "'\n";
+ });
+ continue;
}
}
}
- // Compute the require features.
- ListInit *Predicates = CGI.TheDef->getValueAsListInit("Predicates");
- for (unsigned i = 0, e = Predicates->getSize(); i != e; ++i) {
- if (DefInit *Pred = dynamic_cast<DefInit*>(Predicates->getElement(i))) {
- // Ignore OptForSize and OptForSpeed, they aren't really requirements,
- // rather they are hints to isel.
- //
- // FIXME: Find better way to model this.
- if (Pred->getDef()->getName() == "OptForSize" ||
- Pred->getDef()->getName() == "OptForSpeed")
- continue;
+ OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
- // FIXME: Total hack; for now, we just limit ourselves to In32BitMode
- // and In64BitMode, because we aren't going to have the right feature
- // masks for SSE and friends. We need to decide what we are going to do
- // about CPU subtypes to implement this the right way.
- if (Pred->getDef()->getName() != "In32BitMode" &&
- Pred->getDef()->getName() != "In64BitMode")
- continue;
+ II->Initialize(*this, SingletonRegisters);
- II->RequiredFeatures.push_back(getSubtargetFeature(Pred->getDef()));
- }
- }
+ // Ignore instructions which shouldn't be matched and diagnose invalid
+ // instruction definitions with an error.
+ if (!II->Validate(CommentDelimiter, true))
+ continue;
- Instructions.push_back(II.take());
+ // Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
+ //
+ // FIXME: This is a total hack.
+ if (StringRef(II->TheDef->getName()).startswith("Int_") ||
+ StringRef(II->TheDef->getName()).endswith("_Int"))
+ continue;
+
+ Matchables.push_back(II.take());
+ }
+
+ // Parse all of the InstAlias definitions and stick them in the list of
+ // matchables.
+ std::vector<Record*> AllInstAliases =
+ Records.getAllDerivedDefinitions("InstAlias");
+ for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) {
+ CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target);
+
+ // If the tblgen -match-prefix option is specified (for tblgen hackers),
+ // filter the set of instruction aliases we consider, based on the target
+ // instruction.
+ if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith(
+ MatchPrefix))
+ continue;
+
+ OwningPtr<MatchableInfo> II(new MatchableInfo(Alias));
+
+ II->Initialize(*this, SingletonRegisters);
+
+ // Validate the alias definitions.
+ II->Validate(CommentDelimiter, false);
+
+ Matchables.push_back(II.take());
}
// Build info for the register classes.
- BuildRegisterClasses(Target, SingletonRegisterNames);
+ BuildRegisterClasses(SingletonRegisters);
// Build info for the user defined assembly operand classes.
- BuildOperandClasses(Target);
+ BuildOperandClasses();
- // Build the instruction information.
- for (std::vector<InstructionInfo*>::iterator it = Instructions.begin(),
- ie = Instructions.end(); it != ie; ++it) {
- InstructionInfo *II = *it;
+ // Build the information about matchables, now that we have fully formed
+ // classes.
+ for (std::vector<MatchableInfo*>::iterator it = Matchables.begin(),
+ ie = Matchables.end(); it != ie; ++it) {
+ MatchableInfo *II = *it;
- for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) {
- StringRef Token = II->Tokens[i];
+ // Parse the tokens after the mnemonic.
+ // Note: BuildInstructionOperandReference may insert new AsmOperands, so
+ // don't precompute the loop bound.
+ for (unsigned i = 0; i != II->AsmOperands.size(); ++i) {
+ MatchableInfo::AsmOperand &Op = II->AsmOperands[i];
+ StringRef Token = Op.Token;
// Check for singleton registers.
- if (!RegisterPrefix.empty() && Token.startswith(RegisterPrefix)) {
- StringRef RegName = II->Tokens[i].substr(RegisterPrefix.size());
- InstructionInfo::Operand Op;
- Op.Class = RegisterClasses[getRegisterRecord(Target, RegName)];
- Op.OperandInfo = 0;
+ if (Record *RegRecord = II->getSingletonRegisterForAsmOperand(i, *this)) {
+ Op.Class = RegisterClasses[RegRecord];
assert(Op.Class && Op.Class->Registers.size() == 1 &&
"Unexpected class for singleton register");
- II->Operands.push_back(Op);
continue;
}
// Check for simple tokens.
if (Token[0] != '$') {
- InstructionInfo::Operand Op;
Op.Class = getTokenClass(Token);
- Op.OperandInfo = 0;
- II->Operands.push_back(Op);
+ continue;
+ }
+
+ if (Token.size() > 1 && isdigit(Token[1])) {
+ Op.Class = getTokenClass(Token);
continue;
}
@@ -1022,58 +1253,204 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
else
OperandName = Token.substr(1);
- // Map this token to an operand. FIXME: Move elsewhere.
- unsigned Idx;
- try {
- Idx = II->Instr->getOperandNamed(OperandName);
- } catch(...) {
- throw std::string("error: unable to find operand: '" +
- OperandName.str() + "'");
- }
+ if (II->DefRec.is<const CodeGenInstruction*>())
+ BuildInstructionOperandReference(II, OperandName, i);
+ else
+ BuildAliasOperandReference(II, OperandName, Op);
+ }
- // FIXME: This is annoying, the named operand may be tied (e.g.,
- // XCHG8rm). What we want is the untied operand, which we now have to
- // grovel for. Only worry about this for single entry operands, we have to
- // clean this up anyway.
- const CodeGenInstruction::OperandInfo *OI = &II->Instr->OperandList[Idx];
- if (OI->Constraints[0].isTied()) {
- unsigned TiedOp = OI->Constraints[0].getTiedOperand();
-
- // The tied operand index is an MIOperand index, find the operand that
- // contains it.
- for (unsigned i = 0, e = II->Instr->OperandList.size(); i != e; ++i) {
- if (II->Instr->OperandList[i].MIOperandNo == TiedOp) {
- OI = &II->Instr->OperandList[i];
- break;
- }
- }
+ if (II->DefRec.is<const CodeGenInstruction*>())
+ II->BuildInstructionResultOperands();
+ else
+ II->BuildAliasResultOperands();
+ }
- assert(OI && "Unable to find tied operand target!");
- }
+ // Reorder classes so that classes preceed super classes.
+ std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
+}
- InstructionInfo::Operand Op;
- Op.Class = getOperandClass(Token, *OI);
- Op.OperandInfo = OI;
- II->Operands.push_back(Op);
+/// BuildInstructionOperandReference - The specified operand is a reference to a
+/// named operand such as $src. Resolve the Class and OperandInfo pointers.
+void AsmMatcherInfo::
+BuildInstructionOperandReference(MatchableInfo *II,
+ StringRef OperandName,
+ unsigned AsmOpIdx) {
+ const CodeGenInstruction &CGI = *II->DefRec.get<const CodeGenInstruction*>();
+ const CGIOperandList &Operands = CGI.Operands;
+ MatchableInfo::AsmOperand *Op = &II->AsmOperands[AsmOpIdx];
+
+ // Map this token to an operand.
+ unsigned Idx;
+ if (!Operands.hasOperandNamed(OperandName, Idx))
+ throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" +
+ OperandName.str() + "'");
+
+ // If the instruction operand has multiple suboperands, but the parser
+ // match class for the asm operand is still the default "ImmAsmOperand",
+ // then handle each suboperand separately.
+ if (Op->SubOpIdx == -1 && Operands[Idx].MINumOperands > 1) {
+ Record *Rec = Operands[Idx].Rec;
+ assert(Rec->isSubClassOf("Operand") && "Unexpected operand!");
+ Record *MatchClass = Rec->getValueAsDef("ParserMatchClass");
+ if (MatchClass && MatchClass->getValueAsString("Name") == "Imm") {
+ // Insert remaining suboperands after AsmOpIdx in II->AsmOperands.
+ StringRef Token = Op->Token; // save this in case Op gets moved
+ for (unsigned SI = 1, SE = Operands[Idx].MINumOperands; SI != SE; ++SI) {
+ MatchableInfo::AsmOperand NewAsmOp(Token);
+ NewAsmOp.SubOpIdx = SI;
+ II->AsmOperands.insert(II->AsmOperands.begin()+AsmOpIdx+SI, NewAsmOp);
+ }
+ // Replace Op with first suboperand.
+ Op = &II->AsmOperands[AsmOpIdx]; // update the pointer in case it moved
+ Op->SubOpIdx = 0;
}
}
- // Reorder classes so that classes preceed super classes.
- std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
+ // Set up the operand class.
+ Op->Class = getOperandClass(Operands[Idx], Op->SubOpIdx);
+
+ // If the named operand is tied, canonicalize it to the untied operand.
+ // For example, something like:
+ // (outs GPR:$dst), (ins GPR:$src)
+ // with an asmstring of
+ // "inc $src"
+ // we want to canonicalize to:
+ // "inc $dst"
+ // so that we know how to provide the $dst operand when filling in the result.
+ int OITied = Operands[Idx].getTiedRegister();
+ if (OITied != -1) {
+ // The tied operand index is an MIOperand index, find the operand that
+ // contains it.
+ std::pair<unsigned, unsigned> Idx = Operands.getSubOperandNumber(OITied);
+ OperandName = Operands[Idx.first].Name;
+ Op->SubOpIdx = Idx.second;
+ }
+
+ Op->SrcOpName = OperandName;
}
-static std::pair<unsigned, unsigned> *
-GetTiedOperandAtIndex(SmallVectorImpl<std::pair<unsigned, unsigned> > &List,
- unsigned Index) {
- for (unsigned i = 0, e = List.size(); i != e; ++i)
- if (Index == List[i].first)
- return &List[i];
+/// BuildAliasOperandReference - When parsing an operand reference out of the
+/// matching string (e.g. "movsx $src, $dst"), determine what the class of the
+/// operand reference is by looking it up in the result pattern definition.
+void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
+ StringRef OperandName,
+ MatchableInfo::AsmOperand &Op) {
+ const CodeGenInstAlias &CGA = *II->DefRec.get<const CodeGenInstAlias*>();
+
+ // Set up the operand class.
+ for (unsigned i = 0, e = CGA.ResultOperands.size(); i != e; ++i)
+ if (CGA.ResultOperands[i].isRecord() &&
+ CGA.ResultOperands[i].getName() == OperandName) {
+ // It's safe to go with the first one we find, because CodeGenInstAlias
+ // validates that all operands with the same name have the same record.
+ unsigned ResultIdx = CGA.ResultInstOperandIndex[i].first;
+ Op.SubOpIdx = CGA.ResultInstOperandIndex[i].second;
+ Op.Class = getOperandClass(CGA.ResultInst->Operands[ResultIdx],
+ Op.SubOpIdx);
+ Op.SrcOpName = OperandName;
+ return;
+ }
+
+ throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" +
+ OperandName.str() + "'");
+}
+
+void MatchableInfo::BuildInstructionResultOperands() {
+ const CodeGenInstruction *ResultInst = getResultInst();
+
+ // Loop over all operands of the result instruction, determining how to
+ // populate them.
+ for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
+ const CGIOperandList::OperandInfo &OpInfo = ResultInst->Operands[i];
+
+ // If this is a tied operand, just copy from the previously handled operand.
+ int TiedOp = OpInfo.getTiedRegister();
+ if (TiedOp != -1) {
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
+ continue;
+ }
+
+ // Find out what operand from the asmparser this MCInst operand comes from.
+ int SrcOperand = FindAsmOperandNamed(OpInfo.Name);
+ if (OpInfo.Name.empty() || SrcOperand == -1)
+ throw TGError(TheDef->getLoc(), "Instruction '" +
+ TheDef->getName() + "' has operand '" + OpInfo.Name +
+ "' that doesn't appear in asm string!");
+
+ // Check if the one AsmOperand populates the entire operand.
+ unsigned NumOperands = OpInfo.MINumOperands;
+ if (AsmOperands[SrcOperand].SubOpIdx == -1) {
+ ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, NumOperands));
+ continue;
+ }
- return 0;
+ // Add a separate ResOperand for each suboperand.
+ for (unsigned AI = 0; AI < NumOperands; ++AI) {
+ assert(AsmOperands[SrcOperand+AI].SubOpIdx == (int)AI &&
+ AsmOperands[SrcOperand+AI].SrcOpName == OpInfo.Name &&
+ "unexpected AsmOperands for suboperands");
+ ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand + AI, 1));
+ }
+ }
}
-static void EmitConvertToMCInst(CodeGenTarget &Target,
- std::vector<InstructionInfo*> &Infos,
+void MatchableInfo::BuildAliasResultOperands() {
+ const CodeGenInstAlias &CGA = *DefRec.get<const CodeGenInstAlias*>();
+ const CodeGenInstruction *ResultInst = getResultInst();
+
+ // Loop over all operands of the result instruction, determining how to
+ // populate them.
+ unsigned AliasOpNo = 0;
+ unsigned LastOpNo = CGA.ResultInstOperandIndex.size();
+ for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
+ const CGIOperandList::OperandInfo *OpInfo = &ResultInst->Operands[i];
+
+ // If this is a tied operand, just copy from the previously handled operand.
+ int TiedOp = OpInfo->getTiedRegister();
+ if (TiedOp != -1) {
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
+ continue;
+ }
+
+ // Handle all the suboperands for this operand.
+ const std::string &OpName = OpInfo->Name;
+ for ( ; AliasOpNo < LastOpNo &&
+ CGA.ResultInstOperandIndex[AliasOpNo].first == i; ++AliasOpNo) {
+ int SubIdx = CGA.ResultInstOperandIndex[AliasOpNo].second;
+
+ // Find out what operand from the asmparser that this MCInst operand
+ // comes from.
+ switch (CGA.ResultOperands[AliasOpNo].Kind) {
+ default: assert(0 && "unexpected InstAlias operand kind");
+ case CodeGenInstAlias::ResultOperand::K_Record: {
+ StringRef Name = CGA.ResultOperands[AliasOpNo].getName();
+ int SrcOperand = FindAsmOperand(Name, SubIdx);
+ if (SrcOperand == -1)
+ throw TGError(TheDef->getLoc(), "Instruction '" +
+ TheDef->getName() + "' has operand '" + OpName +
+ "' that doesn't appear in asm string!");
+ unsigned NumOperands = (SubIdx == -1 ? OpInfo->MINumOperands : 1);
+ ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand,
+ NumOperands));
+ break;
+ }
+ case CodeGenInstAlias::ResultOperand::K_Imm: {
+ int64_t ImmVal = CGA.ResultOperands[AliasOpNo].getImm();
+ ResOperands.push_back(ResOperand::getImmOp(ImmVal));
+ break;
+ }
+ case CodeGenInstAlias::ResultOperand::K_Reg: {
+ Record *Reg = CGA.ResultOperands[AliasOpNo].getRegister();
+ ResOperands.push_back(ResOperand::getRegOp(Reg));
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void EmitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
+ std::vector<MatchableInfo*> &Infos,
raw_ostream &OS) {
// Write the convert function to a separate stream, so we can drop it after
// the enum.
@@ -1084,8 +1461,8 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
std::set<std::string> GeneratedFns;
// Start the unified conversion function.
-
- CvtOS << "static void ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
+ CvtOS << "bool " << Target.getName() << ClassName << "::\n";
+ CvtOS << "ConvertToMCInst(unsigned Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
<< " const SmallVectorImpl<MCParsedAsmOperand*"
<< "> &Operands) {\n";
@@ -1095,92 +1472,94 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
// Start the enum, which we will generate inline.
- OS << "// Unified function for converting operants to MCInst instances.\n\n";
+ OS << "// Unified function for converting operands to MCInst instances.\n\n";
OS << "enum ConversionKind {\n";
-
+
// TargetOperandClass - This is the target's operand class, like X86Operand.
std::string TargetOperandClass = Target.getName() + "Operand";
-
- for (std::vector<InstructionInfo*>::const_iterator it = Infos.begin(),
+
+ for (std::vector<MatchableInfo*>::const_iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) {
- InstructionInfo &II = **it;
-
- // Order the (class) operands by the order to convert them into an MCInst.
- SmallVector<std::pair<unsigned, unsigned>, 4> MIOperandList;
- for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) {
- InstructionInfo::Operand &Op = II.Operands[i];
- if (Op.OperandInfo)
- MIOperandList.push_back(std::make_pair(Op.OperandInfo->MIOperandNo, i));
- }
+ MatchableInfo &II = **it;
- // Find any tied operands.
- SmallVector<std::pair<unsigned, unsigned>, 4> TiedOperands;
- for (unsigned i = 0, e = II.Instr->OperandList.size(); i != e; ++i) {
- const CodeGenInstruction::OperandInfo &OpInfo = II.Instr->OperandList[i];
- for (unsigned j = 0, e = OpInfo.Constraints.size(); j != e; ++j) {
- const CodeGenInstruction::ConstraintInfo &CI = OpInfo.Constraints[j];
- if (CI.isTied())
- TiedOperands.push_back(std::make_pair(OpInfo.MIOperandNo + j,
- CI.getTiedOperand()));
- }
- }
+ // Check if we have a custom match function.
+ StringRef AsmMatchConverter = II.getResultInst()->TheDef->getValueAsString(
+ "AsmMatchConverter");
+ if (!AsmMatchConverter.empty()) {
+ std::string Signature = "ConvertCustom_" + AsmMatchConverter.str();
+ II.ConversionFnKind = Signature;
- std::sort(MIOperandList.begin(), MIOperandList.end());
+ // Check if we have already generated this signature.
+ if (!GeneratedFns.insert(Signature).second)
+ continue;
- // Compute the total number of operands.
- unsigned NumMIOperands = 0;
- for (unsigned i = 0, e = II.Instr->OperandList.size(); i != e; ++i) {
- const CodeGenInstruction::OperandInfo &OI = II.Instr->OperandList[i];
- NumMIOperands = std::max(NumMIOperands,
- OI.MIOperandNo + OI.MINumOperands);
+ // If not, emit it now. Add to the enum list.
+ OS << " " << Signature << ",\n";
+
+ CvtOS << " case " << Signature << ":\n";
+ CvtOS << " return " << AsmMatchConverter
+ << "(Inst, Opcode, Operands);\n";
+ continue;
}
// Build the conversion function signature.
std::string Signature = "Convert";
- unsigned CurIndex = 0;
- for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) {
- InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second];
- assert(CurIndex <= Op.OperandInfo->MIOperandNo &&
- "Duplicate match for instruction operand!");
-
- // Skip operands which weren't matched by anything, this occurs when the
- // .td file encodes "implicit" operands as explicit ones.
- //
- // FIXME: This should be removed from the MCInst structure.
- for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) {
- std::pair<unsigned, unsigned> *Tie = GetTiedOperandAtIndex(TiedOperands,
- CurIndex);
- if (!Tie)
- Signature += "__Imp";
+ std::string CaseBody;
+ raw_string_ostream CaseOS(CaseBody);
+
+ // Compute the convert enum and the case body.
+ for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) {
+ const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i];
+
+ // Generate code to populate each result operand.
+ switch (OpInfo.Kind) {
+ case MatchableInfo::ResOperand::RenderAsmOperand: {
+ // This comes from something we parsed.
+ MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum];
+
+ // Registers are always converted the same, don't duplicate the
+ // conversion function based on them.
+ Signature += "__";
+ if (Op.Class->isRegisterClass())
+ Signature += "Reg";
else
- Signature += "__Tie" + utostr(Tie->second);
- }
-
- Signature += "__";
-
- // Registers are always converted the same, don't duplicate the conversion
- // function based on them.
- //
- // FIXME: We could generalize this based on the render method, if it
- // mattered.
- if (Op.Class->isRegisterClass())
- Signature += "Reg";
- else
- Signature += Op.Class->ClassName;
- Signature += utostr(Op.OperandInfo->MINumOperands);
- Signature += "_" + utostr(MIOperandList[i].second);
+ Signature += Op.Class->ClassName;
+ Signature += utostr(OpInfo.MINumOperands);
+ Signature += "_" + itostr(OpInfo.AsmOperandNum);
- CurIndex += Op.OperandInfo->MINumOperands;
- }
+ CaseOS << " ((" << TargetOperandClass << "*)Operands["
+ << (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod
+ << "(Inst, " << OpInfo.MINumOperands << ");\n";
+ break;
+ }
- // Add any trailing implicit operands.
- for (; CurIndex != NumMIOperands; ++CurIndex) {
- std::pair<unsigned, unsigned> *Tie = GetTiedOperandAtIndex(TiedOperands,
- CurIndex);
- if (!Tie)
- Signature += "__Imp";
- else
- Signature += "__Tie" + utostr(Tie->second);
+ case MatchableInfo::ResOperand::TiedOperand: {
+ // If this operand is tied to a previous one, just copy the MCInst
+ // operand from the earlier one.We can only tie single MCOperand values.
+ //assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand");
+ unsigned TiedOp = OpInfo.TiedOperandNum;
+ assert(i > TiedOp && "Tied operand preceeds its target!");
+ CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n";
+ Signature += "__Tie" + utostr(TiedOp);
+ break;
+ }
+ case MatchableInfo::ResOperand::ImmOperand: {
+ int64_t Val = OpInfo.ImmVal;
+ CaseOS << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n";
+ Signature += "__imm" + itostr(Val);
+ break;
+ }
+ case MatchableInfo::ResOperand::RegOperand: {
+ if (OpInfo.Register == 0) {
+ CaseOS << " Inst.addOperand(MCOperand::CreateReg(0));\n";
+ Signature += "__reg0";
+ } else {
+ std::string N = getQualifiedName(OpInfo.Register);
+ CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n";
+ Signature += "__reg" + OpInfo.Register->getName();
+ }
+ }
+ }
}
II.ConversionFnKind = Signature;
@@ -1189,72 +1568,25 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
if (!GeneratedFns.insert(Signature).second)
continue;
- // If not, emit it now.
-
- // Add to the enum list.
+ // If not, emit it now. Add to the enum list.
OS << " " << Signature << ",\n";
- // And to the convert function.
CvtOS << " case " << Signature << ":\n";
- CurIndex = 0;
- for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) {
- InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second];
-
- // Add the implicit operands.
- for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) {
- // See if this is a tied operand.
- std::pair<unsigned, unsigned> *Tie = GetTiedOperandAtIndex(TiedOperands,
- CurIndex);
-
- if (!Tie) {
- // If not, this is some implicit operand. Just assume it is a register
- // for now.
- CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n";
- } else {
- // Copy the tied operand.
- assert(Tie->first>Tie->second && "Tied operand preceeds its target!");
- CvtOS << " Inst.addOperand(Inst.getOperand("
- << Tie->second << "));\n";
- }
- }
-
- CvtOS << " ((" << TargetOperandClass << "*)Operands["
- << MIOperandList[i].second
- << "])->" << Op.Class->RenderMethod
- << "(Inst, " << Op.OperandInfo->MINumOperands << ");\n";
- CurIndex += Op.OperandInfo->MINumOperands;
- }
-
- // And add trailing implicit operands.
- for (; CurIndex != NumMIOperands; ++CurIndex) {
- std::pair<unsigned, unsigned> *Tie = GetTiedOperandAtIndex(TiedOperands,
- CurIndex);
-
- if (!Tie) {
- // If not, this is some implicit operand. Just assume it is a register
- // for now.
- CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n";
- } else {
- // Copy the tied operand.
- assert(Tie->first>Tie->second && "Tied operand preceeds its target!");
- CvtOS << " Inst.addOperand(Inst.getOperand("
- << Tie->second << "));\n";
- }
- }
-
- CvtOS << " return;\n";
+ CvtOS << CaseOS.str();
+ CvtOS << " return true;\n";
}
// Finish the convert function.
CvtOS << " }\n";
+ CvtOS << " return false;\n";
CvtOS << "}\n\n";
// Finish the enum, and drop the convert function after it.
OS << " NumConversionVariants\n";
OS << "};\n\n";
-
+
OS << CvtOS.str();
}
@@ -1268,7 +1600,7 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
<< "/// instruction matching.\n";
OS << "enum MatchClassKind {\n";
OS << " InvalidMatchClass = 0,\n";
- for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
+ for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) {
ClassInfo &CI = **it;
OS << " " << CI.Name << ", // ";
@@ -1289,64 +1621,50 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitClassifyOperand - Emit the function to classify an operand.
-static void EmitClassifyOperand(CodeGenTarget &Target,
- AsmMatcherInfo &Info,
- raw_ostream &OS) {
- OS << "static MatchClassKind ClassifyOperand(MCParsedAsmOperand *GOp) {\n"
- << " " << Target.getName() << "Operand &Operand = *("
- << Target.getName() << "Operand*)GOp;\n";
+/// EmitValidateOperandClass - Emit the function to validate an operand class.
+static void EmitValidateOperandClass(AsmMatcherInfo &Info,
+ raw_ostream &OS) {
+ OS << "static bool ValidateOperandClass(MCParsedAsmOperand *GOp, "
+ << "MatchClassKind Kind) {\n";
+ OS << " " << Info.Target.getName() << "Operand &Operand = *("
+ << Info.Target.getName() << "Operand*)GOp;\n";
- // Classify tokens.
+ // Check for Token operands first.
OS << " if (Operand.isToken())\n";
- OS << " return MatchTokenString(Operand.getToken());\n\n";
+ OS << " return MatchTokenString(Operand.getToken()) == Kind;\n\n";
- // Classify registers.
- //
- // FIXME: Don't hardcode isReg, getReg.
+ // Check for register operands, including sub-classes.
OS << " if (Operand.isReg()) {\n";
+ OS << " MatchClassKind OpKind;\n";
OS << " switch (Operand.getReg()) {\n";
- OS << " default: return InvalidMatchClass;\n";
- for (std::map<Record*, ClassInfo*>::iterator
+ OS << " default: OpKind = InvalidMatchClass; break;\n";
+ for (std::map<Record*, ClassInfo*>::iterator
it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end();
it != ie; ++it)
- OS << " case " << Target.getName() << "::"
- << it->first->getName() << ": return " << it->second->Name << ";\n";
+ OS << " case " << Info.Target.getName() << "::"
+ << it->first->getName() << ": OpKind = " << it->second->Name
+ << "; break;\n";
OS << " }\n";
+ OS << " return IsSubclass(OpKind, Kind);\n";
OS << " }\n\n";
- // Classify user defined operands.
- for (std::vector<ClassInfo*>::iterator it = Info.Classes.begin(),
+ // Check the user classes. We don't care what order since we're only
+ // actually matching against one of them.
+ for (std::vector<ClassInfo*>::iterator it = Info.Classes.begin(),
ie = Info.Classes.end(); it != ie; ++it) {
ClassInfo &CI = **it;
if (!CI.isUserClass())
continue;
- OS << " // '" << CI.ClassName << "' class";
- if (!CI.SuperClasses.empty()) {
- OS << ", subclass of ";
- for (unsigned i = 0, e = CI.SuperClasses.size(); i != e; ++i) {
- if (i) OS << ", ";
- OS << "'" << CI.SuperClasses[i]->ClassName << "'";
- assert(CI < *CI.SuperClasses[i] && "Invalid class relation!");
- }
- }
- OS << "\n";
-
- OS << " if (Operand." << CI.PredicateMethod << "()) {\n";
-
- // Validate subclass relationships.
- if (!CI.SuperClasses.empty()) {
- for (unsigned i = 0, e = CI.SuperClasses.size(); i != e; ++i)
- OS << " assert(Operand." << CI.SuperClasses[i]->PredicateMethod
- << "() && \"Invalid class relationship!\");\n";
- }
-
- OS << " return " << CI.Name << ";\n";
+ OS << " // '" << CI.ClassName << "' class\n";
+ OS << " if (Kind == " << CI.Name
+ << " && Operand." << CI.PredicateMethod << "()) {\n";
+ OS << " return true;\n";
OS << " }\n\n";
}
- OS << " return InvalidMatchClass;\n";
+
+ OS << " return false;\n";
OS << "}\n\n";
}
@@ -1362,13 +1680,13 @@ static void EmitIsSubclass(CodeGenTarget &Target,
OS << " switch (A) {\n";
OS << " default:\n";
OS << " return false;\n";
- for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
+ for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) {
ClassInfo &A = **it;
if (A.Kind != ClassInfo::Token) {
std::vector<StringRef> SuperClasses;
- for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
+ for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) {
ClassInfo &B = **it;
@@ -1397,153 +1715,25 @@ static void EmitIsSubclass(CodeGenTarget &Target,
OS << "}\n\n";
}
-typedef std::pair<std::string, std::string> StringPair;
-
-/// FindFirstNonCommonLetter - Find the first character in the keys of the
-/// string pairs that is not shared across the whole set of strings. All
-/// strings are assumed to have the same length.
-static unsigned
-FindFirstNonCommonLetter(const std::vector<const StringPair*> &Matches) {
- assert(!Matches.empty());
- for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) {
- // Check to see if letter i is the same across the set.
- char Letter = Matches[0]->first[i];
-
- for (unsigned str = 0, e = Matches.size(); str != e; ++str)
- if (Matches[str]->first[i] != Letter)
- return i;
- }
-
- return Matches[0]->first.size();
-}
-
-/// EmitStringMatcherForChar - Given a set of strings that are known to be the
-/// same length and whose characters leading up to CharNo are the same, emit
-/// code to verify that CharNo and later are the same.
-///
-/// \return - True if control can leave the emitted code fragment.
-static bool EmitStringMatcherForChar(const std::string &StrVariableName,
- const std::vector<const StringPair*> &Matches,
- unsigned CharNo, unsigned IndentCount,
- raw_ostream &OS) {
- assert(!Matches.empty() && "Must have at least one string to match!");
- std::string Indent(IndentCount*2+4, ' ');
-
- // If we have verified that the entire string matches, we're done: output the
- // matching code.
- if (CharNo == Matches[0]->first.size()) {
- assert(Matches.size() == 1 && "Had duplicate keys to match on");
-
- // FIXME: If Matches[0].first has embeded \n, this will be bad.
- OS << Indent << Matches[0]->second << "\t // \"" << Matches[0]->first
- << "\"\n";
- return false;
- }
-
- // Bucket the matches by the character we are comparing.
- std::map<char, std::vector<const StringPair*> > MatchesByLetter;
-
- for (unsigned i = 0, e = Matches.size(); i != e; ++i)
- MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]);
-
-
- // If we have exactly one bucket to match, see how many characters are common
- // across the whole set and match all of them at once.
- if (MatchesByLetter.size() == 1) {
- unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches);
- unsigned NumChars = FirstNonCommonLetter-CharNo;
-
- // Emit code to break out if the prefix doesn't match.
- if (NumChars == 1) {
- // Do the comparison with if (Str[1] != 'f')
- // FIXME: Need to escape general characters.
- OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '"
- << Matches[0]->first[CharNo] << "')\n";
- OS << Indent << " break;\n";
- } else {
- // Do the comparison with if (Str.substr(1,3) != "foo").
- // FIXME: Need to escape general strings.
- OS << Indent << "if (" << StrVariableName << ".substr(" << CharNo << ","
- << NumChars << ") != \"";
- OS << Matches[0]->first.substr(CharNo, NumChars) << "\")\n";
- OS << Indent << " break;\n";
- }
-
- return EmitStringMatcherForChar(StrVariableName, Matches,
- FirstNonCommonLetter, IndentCount, OS);
- }
-
- // Otherwise, we have multiple possible things, emit a switch on the
- // character.
- OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n";
- OS << Indent << "default: break;\n";
-
- for (std::map<char, std::vector<const StringPair*> >::iterator LI =
- MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) {
- // TODO: escape hard stuff (like \n) if we ever care about it.
- OS << Indent << "case '" << LI->first << "':\t // "
- << LI->second.size() << " strings to match.\n";
- if (EmitStringMatcherForChar(StrVariableName, LI->second, CharNo+1,
- IndentCount+1, OS))
- OS << Indent << " break;\n";
- }
-
- OS << Indent << "}\n";
- return true;
-}
-
-
-/// EmitStringMatcher - Given a list of strings and code to execute when they
-/// match, output a simple switch tree to classify the input string.
-///
-/// If a match is found, the code in Vals[i].second is executed; control must
-/// not exit this code fragment. If nothing matches, execution falls through.
-///
-/// \param StrVariableName - The name of the variable to test.
-static void EmitStringMatcher(const std::string &StrVariableName,
- const std::vector<StringPair> &Matches,
- raw_ostream &OS) {
- // First level categorization: group strings by length.
- std::map<unsigned, std::vector<const StringPair*> > MatchesByLength;
-
- for (unsigned i = 0, e = Matches.size(); i != e; ++i)
- MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]);
-
- // Output a switch statement on length and categorize the elements within each
- // bin.
- OS << " switch (" << StrVariableName << ".size()) {\n";
- OS << " default: break;\n";
-
- for (std::map<unsigned, std::vector<const StringPair*> >::iterator LI =
- MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) {
- OS << " case " << LI->first << ":\t // " << LI->second.size()
- << " strings to match.\n";
- if (EmitStringMatcherForChar(StrVariableName, LI->second, 0, 0, OS))
- OS << " break;\n";
- }
-
- OS << " }\n";
-}
-
-
/// EmitMatchTokenString - Emit the function to match a token string to the
/// appropriate match class value.
static void EmitMatchTokenString(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
// Construct the match list.
- std::vector<StringPair> Matches;
- for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
+ std::vector<StringMatcher::StringPair> Matches;
+ for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) {
ClassInfo &CI = **it;
if (CI.Kind == ClassInfo::Token)
- Matches.push_back(StringPair(CI.ValueName, "return " + CI.Name + ";"));
+ Matches.push_back(StringMatcher::StringPair(CI.ValueName,
+ "return " + CI.Name + ";"));
}
OS << "static MatchClassKind MatchTokenString(StringRef Name) {\n";
- EmitStringMatcher("Name", Matches, OS);
+ StringMatcher("Name", Matches, OS).Emit();
OS << " return InvalidMatchClass;\n";
OS << "}\n\n";
@@ -1554,28 +1744,28 @@ static void EmitMatchTokenString(CodeGenTarget &Target,
static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
raw_ostream &OS) {
// Construct the match list.
- std::vector<StringPair> Matches;
+ std::vector<StringMatcher::StringPair> Matches;
for (unsigned i = 0, e = Target.getRegisters().size(); i != e; ++i) {
const CodeGenRegister &Reg = Target.getRegisters()[i];
if (Reg.TheDef->getValueAsString("AsmName").empty())
continue;
- Matches.push_back(StringPair(Reg.TheDef->getValueAsString("AsmName"),
- "return " + utostr(i + 1) + ";"));
+ Matches.push_back(StringMatcher::StringPair(
+ Reg.TheDef->getValueAsString("AsmName"),
+ "return " + utostr(i + 1) + ";"));
}
-
+
OS << "static unsigned MatchRegisterName(StringRef Name) {\n";
- EmitStringMatcher("Name", Matches, OS);
-
+ StringMatcher("Name", Matches, OS).Emit();
+
OS << " return 0;\n";
OS << "}\n\n";
}
/// EmitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag
/// definitions.
-static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target,
- AsmMatcherInfo &Info,
+static void EmitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
raw_ostream &OS) {
OS << "// Flags for subtarget features that participate in "
<< "instruction matching.\n";
@@ -1584,7 +1774,7 @@ static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target,
it = Info.SubtargetFeatures.begin(),
ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
SubtargetFeatureInfo &SFI = *it->second;
- OS << " " << SFI.EnumName << " = (1 << " << SFI.Index << "),\n";
+ OS << " " << SFI.getEnumName() << " = (1 << " << SFI.Index << "),\n";
}
OS << " Feature_None = 0\n";
OS << "};\n\n";
@@ -1592,14 +1782,13 @@ static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target,
/// EmitComputeAvailableFeatures - Emit the function to compute the list of
/// available features given a subtarget.
-static void EmitComputeAvailableFeatures(CodeGenTarget &Target,
- AsmMatcherInfo &Info,
+static void EmitComputeAvailableFeatures(AsmMatcherInfo &Info,
raw_ostream &OS) {
std::string ClassName =
Info.AsmParser->getValueAsString("AsmParserClassName");
- OS << "unsigned " << Target.getName() << ClassName << "::\n"
- << "ComputeAvailableFeatures(const " << Target.getName()
+ OS << "unsigned " << Info.Target.getName() << ClassName << "::\n"
+ << "ComputeAvailableFeatures(const " << Info.Target.getName()
<< "Subtarget *Subtarget) const {\n";
OS << " unsigned Features = 0;\n";
for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
@@ -1608,73 +1797,375 @@ static void EmitComputeAvailableFeatures(CodeGenTarget &Target,
SubtargetFeatureInfo &SFI = *it->second;
OS << " if (" << SFI.TheDef->getValueAsString("CondString")
<< ")\n";
- OS << " Features |= " << SFI.EnumName << ";\n";
+ OS << " Features |= " << SFI.getEnumName() << ";\n";
}
OS << " return Features;\n";
OS << "}\n\n";
}
+static std::string GetAliasRequiredFeatures(Record *R,
+ const AsmMatcherInfo &Info) {
+ std::vector<Record*> ReqFeatures = R->getValueAsListOfDefs("Predicates");
+ std::string Result;
+ unsigned NumFeatures = 0;
+ for (unsigned i = 0, e = ReqFeatures.size(); i != e; ++i) {
+ SubtargetFeatureInfo *F = Info.getSubtargetFeature(ReqFeatures[i]);
+
+ if (F == 0)
+ throw TGError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() +
+ "' is not marked as an AssemblerPredicate!");
+
+ if (NumFeatures)
+ Result += '|';
+
+ Result += F->getEnumName();
+ ++NumFeatures;
+ }
+
+ if (NumFeatures > 1)
+ Result = '(' + Result + ')';
+ return Result;
+}
+
+/// EmitMnemonicAliases - If the target has any MnemonicAlias<> definitions,
+/// emit a function for them and return true, otherwise return false.
+static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
+ // Ignore aliases when match-prefix is set.
+ if (!MatchPrefix.empty())
+ return false;
+
+ std::vector<Record*> Aliases =
+ Info.getRecords().getAllDerivedDefinitions("MnemonicAlias");
+ if (Aliases.empty()) return false;
+
+ OS << "static void ApplyMnemonicAliases(StringRef &Mnemonic, "
+ "unsigned Features) {\n";
+
+ // Keep track of all the aliases from a mnemonic. Use an std::map so that the
+ // iteration order of the map is stable.
+ std::map<std::string, std::vector<Record*> > AliasesFromMnemonic;
+
+ for (unsigned i = 0, e = Aliases.size(); i != e; ++i) {
+ Record *R = Aliases[i];
+ AliasesFromMnemonic[R->getValueAsString("FromMnemonic")].push_back(R);
+ }
+
+ // Process each alias a "from" mnemonic at a time, building the code executed
+ // by the string remapper.
+ std::vector<StringMatcher::StringPair> Cases;
+ for (std::map<std::string, std::vector<Record*> >::iterator
+ I = AliasesFromMnemonic.begin(), E = AliasesFromMnemonic.end();
+ I != E; ++I) {
+ const std::vector<Record*> &ToVec = I->second;
+
+ // Loop through each alias and emit code that handles each case. If there
+ // are two instructions without predicates, emit an error. If there is one,
+ // emit it last.
+ std::string MatchCode;
+ int AliasWithNoPredicate = -1;
+
+ for (unsigned i = 0, e = ToVec.size(); i != e; ++i) {
+ Record *R = ToVec[i];
+ std::string FeatureMask = GetAliasRequiredFeatures(R, Info);
+
+ // If this unconditionally matches, remember it for later and diagnose
+ // duplicates.
+ if (FeatureMask.empty()) {
+ if (AliasWithNoPredicate != -1) {
+ // We can't have two aliases from the same mnemonic with no predicate.
+ PrintError(ToVec[AliasWithNoPredicate]->getLoc(),
+ "two MnemonicAliases with the same 'from' mnemonic!");
+ throw TGError(R->getLoc(), "this is the other MnemonicAlias.");
+ }
+
+ AliasWithNoPredicate = i;
+ continue;
+ }
+ if (R->getValueAsString("ToMnemonic") == I->first)
+ throw TGError(R->getLoc(), "MnemonicAlias to the same string");
+
+ if (!MatchCode.empty())
+ MatchCode += "else ";
+ MatchCode += "if ((Features & " + FeatureMask + ") == "+FeatureMask+")\n";
+ MatchCode += " Mnemonic = \"" +R->getValueAsString("ToMnemonic")+"\";\n";
+ }
+
+ if (AliasWithNoPredicate != -1) {
+ Record *R = ToVec[AliasWithNoPredicate];
+ if (!MatchCode.empty())
+ MatchCode += "else\n ";
+ MatchCode += "Mnemonic = \"" + R->getValueAsString("ToMnemonic")+"\";\n";
+ }
+
+ MatchCode += "return;";
+
+ Cases.push_back(std::make_pair(I->first, MatchCode));
+ }
+
+ StringMatcher("Mnemonic", Cases, OS).Emit();
+ OS << "}\n\n";
+
+ return true;
+}
+
+static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
+ const AsmMatcherInfo &Info, StringRef ClassName) {
+ // Emit the static custom operand parsing table;
+ OS << "namespace {\n";
+ OS << " struct OperandMatchEntry {\n";
+ OS << " const char *Mnemonic;\n";
+ OS << " unsigned OperandMask;\n";
+ OS << " MatchClassKind Class;\n";
+ OS << " unsigned RequiredFeatures;\n";
+ OS << " };\n\n";
+
+ OS << " // Predicate for searching for an opcode.\n";
+ OS << " struct LessOpcodeOperand {\n";
+ OS << " bool operator()(const OperandMatchEntry &LHS, StringRef RHS) {\n";
+ OS << " return StringRef(LHS.Mnemonic) < RHS;\n";
+ OS << " }\n";
+ OS << " bool operator()(StringRef LHS, const OperandMatchEntry &RHS) {\n";
+ OS << " return LHS < StringRef(RHS.Mnemonic);\n";
+ OS << " }\n";
+ OS << " bool operator()(const OperandMatchEntry &LHS,";
+ OS << " const OperandMatchEntry &RHS) {\n";
+ OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n";
+ OS << " }\n";
+ OS << " };\n";
+
+ OS << "} // end anonymous namespace.\n\n";
+
+ OS << "static const OperandMatchEntry OperandMatchTable["
+ << Info.OperandMatchInfo.size() << "] = {\n";
+
+ OS << " /* Mnemonic, Operand List Mask, Operand Class, Features */\n";
+ for (std::vector<OperandMatchEntry>::const_iterator it =
+ Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end();
+ it != ie; ++it) {
+ const OperandMatchEntry &OMI = *it;
+ const MatchableInfo &II = *OMI.MI;
+
+ OS << " { \"" << II.Mnemonic << "\""
+ << ", " << OMI.OperandMask;
+
+ OS << " /* ";
+ bool printComma = false;
+ for (int i = 0, e = 31; i !=e; ++i)
+ if (OMI.OperandMask & (1 << i)) {
+ if (printComma)
+ OS << ", ";
+ OS << i;
+ printComma = true;
+ }
+ OS << " */";
+
+ OS << ", " << OMI.CI->Name
+ << ", ";
+
+ // Write the required features mask.
+ if (!II.RequiredFeatures.empty()) {
+ for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) {
+ if (i) OS << "|";
+ OS << II.RequiredFeatures[i]->getEnumName();
+ }
+ } else
+ OS << "0";
+ OS << " },\n";
+ }
+ OS << "};\n\n";
+
+ // Emit the operand class switch to call the correct custom parser for
+ // the found operand class.
+ OS << Target.getName() << ClassName << "::OperandMatchResultTy "
+ << Target.getName() << ClassName << "::\n"
+ << "TryCustomParseOperand(SmallVectorImpl<MCParsedAsmOperand*>"
+ << " &Operands,\n unsigned MCK) {\n\n"
+ << " switch(MCK) {\n";
+
+ for (std::vector<ClassInfo*>::const_iterator it = Info.Classes.begin(),
+ ie = Info.Classes.end(); it != ie; ++it) {
+ ClassInfo *CI = *it;
+ if (CI->ParserMethod.empty())
+ continue;
+ OS << " case " << CI->Name << ":\n"
+ << " return " << CI->ParserMethod << "(Operands);\n";
+ }
+
+ OS << " default:\n";
+ OS << " return MatchOperand_NoMatch;\n";
+ OS << " }\n";
+ OS << " return MatchOperand_NoMatch;\n";
+ OS << "}\n\n";
+
+ // Emit the static custom operand parser. This code is very similar with
+ // the other matcher. Also use MatchResultTy here just in case we go for
+ // a better error handling.
+ OS << Target.getName() << ClassName << "::OperandMatchResultTy "
+ << Target.getName() << ClassName << "::\n"
+ << "MatchOperandParserImpl(SmallVectorImpl<MCParsedAsmOperand*>"
+ << " &Operands,\n StringRef Mnemonic) {\n";
+
+ // Emit code to get the available features.
+ OS << " // Get the current feature set.\n";
+ OS << " unsigned AvailableFeatures = getAvailableFeatures();\n\n";
+
+ OS << " // Get the next operand index.\n";
+ OS << " unsigned NextOpNum = Operands.size()-1;\n";
+
+ // Emit code to search the table.
+ OS << " // Search the table.\n";
+ OS << " std::pair<const OperandMatchEntry*, const OperandMatchEntry*>";
+ OS << " MnemonicRange =\n";
+ OS << " std::equal_range(OperandMatchTable, OperandMatchTable+"
+ << Info.OperandMatchInfo.size() << ", Mnemonic,\n"
+ << " LessOpcodeOperand());\n\n";
+
+ OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
+ OS << " return MatchOperand_NoMatch;\n\n";
+
+ OS << " for (const OperandMatchEntry *it = MnemonicRange.first,\n"
+ << " *ie = MnemonicRange.second; it != ie; ++it) {\n";
+
+ OS << " // equal_range guarantees that instruction mnemonic matches.\n";
+ OS << " assert(Mnemonic == it->Mnemonic);\n\n";
+
+ // Emit check that the required features are available.
+ OS << " // check if the available features match\n";
+ OS << " if ((AvailableFeatures & it->RequiredFeatures) "
+ << "!= it->RequiredFeatures) {\n";
+ OS << " continue;\n";
+ OS << " }\n\n";
+
+ // Emit check to ensure the operand number matches.
+ OS << " // check if the operand in question has a custom parser.\n";
+ OS << " if (!(it->OperandMask & (1 << NextOpNum)))\n";
+ OS << " continue;\n\n";
+
+ // Emit call to the custom parser method
+ OS << " // call custom parse method to handle the operand\n";
+ OS << " OperandMatchResultTy Result = ";
+ OS << "TryCustomParseOperand(Operands, it->Class);\n";
+ OS << " if (Result != MatchOperand_NoMatch)\n";
+ OS << " return Result;\n";
+ OS << " }\n\n";
+
+ OS << " // Okay, we had no match.\n";
+ OS << " return MatchOperand_NoMatch;\n";
+ OS << "}\n\n";
+}
+
void AsmMatcherEmitter::run(raw_ostream &OS) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
Record *AsmParser = Target.getAsmParser();
std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");
// Compute the information on the instructions to match.
- AsmMatcherInfo Info(AsmParser);
- Info.BuildInfo(Target);
+ AsmMatcherInfo Info(AsmParser, Target, Records);
+ Info.BuildInfo();
// Sort the instruction table using the partial order on classes. We use
// stable_sort to ensure that ambiguous instructions are still
// deterministically ordered.
- std::stable_sort(Info.Instructions.begin(), Info.Instructions.end(),
- less_ptr<InstructionInfo>());
-
+ std::stable_sort(Info.Matchables.begin(), Info.Matchables.end(),
+ less_ptr<MatchableInfo>());
+
DEBUG_WITH_TYPE("instruction_info", {
- for (std::vector<InstructionInfo*>::iterator
- it = Info.Instructions.begin(), ie = Info.Instructions.end();
+ for (std::vector<MatchableInfo*>::iterator
+ it = Info.Matchables.begin(), ie = Info.Matchables.end();
it != ie; ++it)
(*it)->dump();
});
- // Check for ambiguous instructions.
- unsigned NumAmbiguous = 0;
- for (unsigned i = 0, e = Info.Instructions.size(); i != e; ++i) {
- for (unsigned j = i + 1; j != e; ++j) {
- InstructionInfo &A = *Info.Instructions[i];
- InstructionInfo &B = *Info.Instructions[j];
-
- if (A.CouldMatchAmiguouslyWith(B)) {
- DEBUG_WITH_TYPE("ambiguous_instrs", {
- errs() << "warning: ambiguous instruction match:\n";
- A.dump();
- errs() << "\nis incomparable with:\n";
- B.dump();
- errs() << "\n\n";
- });
- ++NumAmbiguous;
+ // Check for ambiguous matchables.
+ DEBUG_WITH_TYPE("ambiguous_instrs", {
+ unsigned NumAmbiguous = 0;
+ for (unsigned i = 0, e = Info.Matchables.size(); i != e; ++i) {
+ for (unsigned j = i + 1; j != e; ++j) {
+ MatchableInfo &A = *Info.Matchables[i];
+ MatchableInfo &B = *Info.Matchables[j];
+
+ if (A.CouldMatchAmbiguouslyWith(B)) {
+ errs() << "warning: ambiguous matchables:\n";
+ A.dump();
+ errs() << "\nis incomparable with:\n";
+ B.dump();
+ errs() << "\n\n";
+ ++NumAmbiguous;
+ }
}
}
- }
- if (NumAmbiguous)
- DEBUG_WITH_TYPE("ambiguous_instrs", {
- errs() << "warning: " << NumAmbiguous
- << " ambiguous instructions!\n";
- });
+ if (NumAmbiguous)
+ errs() << "warning: " << NumAmbiguous
+ << " ambiguous matchables!\n";
+ });
+
+ // Compute the information on the custom operand parsing.
+ Info.BuildOperandMatchInfo();
// Write the output.
EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
+ // Information for the class declaration.
+ OS << "\n#ifdef GET_ASSEMBLER_HEADER\n";
+ OS << "#undef GET_ASSEMBLER_HEADER\n";
+ OS << " // This should be included into the middle of the declaration of\n";
+ OS << " // your subclasses implementation of TargetAsmParser.\n";
+ OS << " unsigned ComputeAvailableFeatures(const " <<
+ Target.getName() << "Subtarget *Subtarget) const;\n";
+ OS << " enum MatchResultTy {\n";
+ OS << " Match_ConversionFail,\n";
+ OS << " Match_InvalidOperand,\n";
+ OS << " Match_MissingFeature,\n";
+ OS << " Match_MnemonicFail,\n";
+ OS << " Match_Success\n";
+ OS << " };\n";
+ OS << " bool ConvertToMCInst(unsigned Kind, MCInst &Inst, "
+ << "unsigned Opcode,\n"
+ << " const SmallVectorImpl<MCParsedAsmOperand*> "
+ << "&Operands);\n";
+ OS << " bool MnemonicIsValid(StringRef Mnemonic);\n";
+ OS << " MatchResultTy MatchInstructionImpl(\n";
+ OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo);\n";
+
+ if (Info.OperandMatchInfo.size()) {
+ OS << "\n enum OperandMatchResultTy {\n";
+ OS << " MatchOperand_Success, // operand matched successfully\n";
+ OS << " MatchOperand_NoMatch, // operand did not match\n";
+ OS << " MatchOperand_ParseFail // operand matched but had errors\n";
+ OS << " };\n";
+ OS << " OperandMatchResultTy MatchOperandParserImpl(\n";
+ OS << " SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
+ OS << " StringRef Mnemonic);\n";
+
+ OS << " OperandMatchResultTy TryCustomParseOperand(\n";
+ OS << " SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
+ OS << " unsigned MCK);\n\n";
+ }
+
+ OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n";
+
+ OS << "\n#ifdef GET_REGISTER_MATCHER\n";
+ OS << "#undef GET_REGISTER_MATCHER\n\n";
+
// Emit the subtarget feature enumeration.
- EmitSubtargetFeatureFlagEnumeration(Target, Info, OS);
+ EmitSubtargetFeatureFlagEnumeration(Info, OS);
// Emit the function to match a register name to number.
EmitMatchRegisterName(Target, AsmParser, OS);
-
- OS << "#ifndef REGISTERS_ONLY\n\n";
+
+ OS << "#endif // GET_REGISTER_MATCHER\n\n";
+
+
+ OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n";
+ OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n";
+
+ // Generate the function that remaps for mnemonic aliases.
+ bool HasMnemonicAliases = EmitMnemonicAliases(OS, Info);
// Generate the unified function to convert operands into an MCInst.
- EmitConvertToMCInst(Target, Info.Instructions, OS);
+ EmitConvertToMCInst(Target, ClassName, Info.Matchables, OS);
// Emit the enumeration for classes which participate in matching.
EmitMatchClassEnumeration(Target, Info.Classes, OS);
@@ -1682,27 +2173,21 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit the routine to match token strings to their match class.
EmitMatchTokenString(Target, Info.Classes, OS);
- // Emit the routine to classify an operand.
- EmitClassifyOperand(Target, Info, OS);
-
// Emit the subclass predicate routine.
EmitIsSubclass(Target, Info.Classes, OS);
+ // Emit the routine to validate an operand against a match class.
+ EmitValidateOperandClass(Info, OS);
+
// Emit the available features compute function.
- EmitComputeAvailableFeatures(Target, Info, OS);
+ EmitComputeAvailableFeatures(Info, OS);
- // Finally, build the match function.
size_t MaxNumOperands = 0;
- for (std::vector<InstructionInfo*>::const_iterator it =
- Info.Instructions.begin(), ie = Info.Instructions.end();
+ for (std::vector<MatchableInfo*>::const_iterator it =
+ Info.Matchables.begin(), ie = Info.Matchables.end();
it != ie; ++it)
- MaxNumOperands = std::max(MaxNumOperands, (*it)->Operands.size());
-
- OS << "bool " << Target.getName() << ClassName << "::\n"
- << "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>"
- << " &Operands,\n";
- OS << " MCInst &Inst) {\n";
+ MaxNumOperands = std::max(MaxNumOperands, (*it)->AsmOperands.size());
// Emit the static match table; unused classes get initalized to 0 which is
// guaranteed to be InvalidMatchClass.
@@ -1714,23 +2199,44 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// order the match kinds appropriately (putting mnemonics last), then we
// should only end up using a few bits for each class, especially the ones
// following the mnemonic.
- OS << " static const struct MatchEntry {\n";
+ OS << "namespace {\n";
+ OS << " struct MatchEntry {\n";
OS << " unsigned Opcode;\n";
+ OS << " const char *Mnemonic;\n";
OS << " ConversionKind ConvertFn;\n";
OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n";
OS << " unsigned RequiredFeatures;\n";
- OS << " } MatchTable[" << Info.Instructions.size() << "] = {\n";
+ OS << " };\n\n";
+
+ OS << " // Predicate for searching for an opcode.\n";
+ OS << " struct LessOpcode {\n";
+ OS << " bool operator()(const MatchEntry &LHS, StringRef RHS) {\n";
+ OS << " return StringRef(LHS.Mnemonic) < RHS;\n";
+ OS << " }\n";
+ OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n";
+ OS << " return LHS < StringRef(RHS.Mnemonic);\n";
+ OS << " }\n";
+ OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n";
+ OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n";
+ OS << " }\n";
+ OS << " };\n";
- for (std::vector<InstructionInfo*>::const_iterator it =
- Info.Instructions.begin(), ie = Info.Instructions.end();
+ OS << "} // end anonymous namespace.\n\n";
+
+ OS << "static const MatchEntry MatchTable["
+ << Info.Matchables.size() << "] = {\n";
+
+ for (std::vector<MatchableInfo*>::const_iterator it =
+ Info.Matchables.begin(), ie = Info.Matchables.end();
it != ie; ++it) {
- InstructionInfo &II = **it;
+ MatchableInfo &II = **it;
- OS << " { " << Target.getName() << "::" << II.InstrName
+ OS << " { " << Target.getName() << "::"
+ << II.getResultInst()->TheDef->getName() << ", \"" << II.Mnemonic << "\""
<< ", " << II.ConversionFnKind << ", { ";
- for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) {
- InstructionInfo::Operand &Op = II.Operands[i];
-
+ for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
+ MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
+
if (i) OS << ", ";
OS << Op.Class->Name;
}
@@ -1740,7 +2246,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (!II.RequiredFeatures.empty()) {
for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) {
if (i) OS << "|";
- OS << II.RequiredFeatures[i]->EnumName;
+ OS << II.RequiredFeatures[i]->getEnumName();
}
} else
OS << "0";
@@ -1748,52 +2254,101 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "},\n";
}
- OS << " };\n\n";
+ OS << "};\n\n";
+
+ // A method to determine if a mnemonic is in the list.
+ OS << "bool " << Target.getName() << ClassName << "::\n"
+ << "MnemonicIsValid(StringRef Mnemonic) {\n";
+ OS << " // Search the table.\n";
+ OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n";
+ OS << " std::equal_range(MatchTable, MatchTable+"
+ << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n";
+ OS << " return MnemonicRange.first != MnemonicRange.second;\n";
+ OS << "}\n\n";
+ // Finally, build the match function.
+ OS << Target.getName() << ClassName << "::MatchResultTy "
+ << Target.getName() << ClassName << "::\n"
+ << "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>"
+ << " &Operands,\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo) {\n";
// Emit code to get the available features.
OS << " // Get the current feature set.\n";
OS << " unsigned AvailableFeatures = getAvailableFeatures();\n\n";
- // Emit code to compute the class list for this operand vector.
- OS << " // Eliminate obvious mismatches.\n";
- OS << " if (Operands.size() > " << MaxNumOperands << ")\n";
- OS << " return true;\n\n";
+ OS << " // Get the instruction mnemonic, which is the first token.\n";
+ OS << " StringRef Mnemonic = ((" << Target.getName()
+ << "Operand*)Operands[0])->getToken();\n\n";
- OS << " // Compute the class list for this operand vector.\n";
- OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n";
- OS << " for (unsigned i = 0, e = Operands.size(); i != e; ++i) {\n";
- OS << " Classes[i] = ClassifyOperand(Operands[i]);\n\n";
+ if (HasMnemonicAliases) {
+ OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
+ OS << " ApplyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
+ }
- OS << " // Check for invalid operands before matching.\n";
- OS << " if (Classes[i] == InvalidMatchClass)\n";
- OS << " return true;\n";
+ // Emit code to compute the class list for this operand vector.
+ OS << " // Eliminate obvious mismatches.\n";
+ OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n";
+ OS << " ErrorInfo = " << (MaxNumOperands+1) << ";\n";
+ OS << " return Match_InvalidOperand;\n";
OS << " }\n\n";
- OS << " // Mark unused classes.\n";
- OS << " for (unsigned i = Operands.size(), e = " << MaxNumOperands << "; "
- << "i != e; ++i)\n";
- OS << " Classes[i] = InvalidMatchClass;\n\n";
+ OS << " // Some state to try to produce better error messages.\n";
+ OS << " bool HadMatchOtherThanFeatures = false;\n\n";
+ OS << " // Set ErrorInfo to the operand that mismatches if it is\n";
+ OS << " // wrong for all instances of the instruction.\n";
+ OS << " ErrorInfo = ~0U;\n";
// Emit code to search the table.
OS << " // Search the table.\n";
- OS << " for (const MatchEntry *it = MatchTable, "
- << "*ie = MatchTable + " << Info.Instructions.size()
- << "; it != ie; ++it) {\n";
+ OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n";
+ OS << " std::equal_range(MatchTable, MatchTable+"
+ << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n\n";
- // Emit check that the required features are available.
- OS << " if ((AvailableFeatures & it->RequiredFeatures) "
- << "!= it->RequiredFeatures)\n";
- OS << " continue;\n";
+ OS << " // Return a more specific error code if no mnemonics match.\n";
+ OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
+ OS << " return Match_MnemonicFail;\n\n";
+
+ OS << " for (const MatchEntry *it = MnemonicRange.first, "
+ << "*ie = MnemonicRange.second;\n";
+ OS << " it != ie; ++it) {\n";
+
+ OS << " // equal_range guarantees that instruction mnemonic matches.\n";
+ OS << " assert(Mnemonic == it->Mnemonic);\n";
// Emit check that the subclasses match.
- for (unsigned i = 0; i != MaxNumOperands; ++i) {
- OS << " if (!IsSubclass(Classes["
- << i << "], it->Classes[" << i << "]))\n";
- OS << " continue;\n";
- }
+ OS << " bool OperandsValid = true;\n";
+ OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n";
+ OS << " if (i + 1 >= Operands.size()) {\n";
+ OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
+ OS << " break;";
+ OS << " }\n";
+ OS << " if (ValidateOperandClass(Operands[i+1], it->Classes[i]))\n";
+ OS << " continue;\n";
+ OS << " // If this operand is broken for all of the instances of this\n";
+ OS << " // mnemonic, keep track of it so we can report loc info.\n";
+ OS << " if (it == MnemonicRange.first || ErrorInfo <= i+1)\n";
+ OS << " ErrorInfo = i+1;\n";
+ OS << " // Otherwise, just reject this instance of the mnemonic.\n";
+ OS << " OperandsValid = false;\n";
+ OS << " break;\n";
+ OS << " }\n\n";
+
+ OS << " if (!OperandsValid) continue;\n";
+
+ // Emit check that the required features are available.
+ OS << " if ((AvailableFeatures & it->RequiredFeatures) "
+ << "!= it->RequiredFeatures) {\n";
+ OS << " HadMatchOtherThanFeatures = true;\n";
+ OS << " continue;\n";
+ OS << " }\n";
+ OS << "\n";
+ OS << " // We have selected a definite instruction, convert the parsed\n"
+ << " // operands into the appropriate MCInst.\n";
+ OS << " if (!ConvertToMCInst(it->ConvertFn, Inst,\n"
+ << " it->Opcode, Operands))\n";
+ OS << " return Match_ConversionFail;\n";
OS << "\n";
- OS << " ConvertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
// Call the post-processing function, if used.
std::string InsnCleanupFn =
@@ -1801,11 +2356,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (!InsnCleanupFn.empty())
OS << " " << InsnCleanupFn << "(Inst);\n";
- OS << " return false;\n";
+ OS << " return Match_Success;\n";
OS << " }\n\n";
- OS << " return true;\n";
+ OS << " // Okay, we had no match. Try to return a useful error code.\n";
+ OS << " if (HadMatchOtherThanFeatures) return Match_MissingFeature;\n";
+ OS << " return Match_InvalidOperand;\n";
OS << "}\n\n";
-
- OS << "#endif // REGISTERS_ONLY\n";
+
+ if (Info.OperandMatchInfo.size())
+ EmitCustomOperandParsing(OS, Target, Info, ClassName);
+
+ OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
}
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index 23f13c2ae2d4..448ebad91f09 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -101,22 +101,22 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
}
void AsmWriterEmitter::
-FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
+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, PROLOG_LABEL, etc.
-
+
std::string Command;
if (Inst->Operands.empty())
continue; // Instruction already done.
@@ -143,13 +143,13 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
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 =
@@ -158,7 +158,7 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
// If this instruction has no more operands, we isn't anything to merge
// into this command.
- const AsmWriterInst *FirstInst =
+ const AsmWriterInst *FirstInst =
getAsmWriterInstByID(NIT-InstIdxs.begin());
if (!FirstInst || FirstInst->Operands.size() == Op)
break;
@@ -175,7 +175,7 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
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 =
+ const AsmWriterInst *OtherInst =
getAsmWriterInstByID(NIT-InstIdxs.begin());
if (OtherInst &&
@@ -189,16 +189,16 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
}
}
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";
-
+
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];
@@ -206,9 +206,9 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
Instrs.erase(Instrs.begin()+70, Instrs.end());
Instrs += "...";
}
-
+
if (!Instrs.empty())
- UniqueOperandCommands[i] = " // " + Instrs + "\n" +
+ UniqueOperandCommands[i] = " // " + Instrs + "\n" +
UniqueOperandCommands[i];
}
}
@@ -240,15 +240,18 @@ static void UnescapeString(std::string &Str) {
/// EmitPrintInstruction - Generate the code for the "printInstruction" method
/// implementation.
void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
-
+ bool isMC = AsmWriter->getValueAsBit("isMCAsmWriter");
+ const char *MachineInstrClassName = isMC ? "MCInst" : "MachineInstr";
+
O <<
"/// printInstruction - This method is automatically generated by tablegen\n"
"/// from the instruction set description.\n"
"void " << Target.getName() << ClassName
- << "::printInstruction(const MachineInstr *MI, raw_ostream &O) {\n";
+ << "::printInstruction(const " << MachineInstrClassName
+ << " *MI, raw_ostream &O) {\n";
std::vector<AsmWriterInst> Instructions;
@@ -257,14 +260,14 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
if (!(*I)->AsmString.empty() &&
(*I)->TheDef->getName() != "PHI")
Instructions.push_back(
- AsmWriterInst(**I,
+ AsmWriterInst(**I,
AsmWriter->getValueAsInt("Variant"),
AsmWriter->getValueAsInt("FirstOperandColumn"),
AsmWriter->getValueAsInt("OperandSpacing")));
// Get the instruction numbering.
NumberedInstructions = Target.getInstructionsByEnumValue();
-
+
// 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.
@@ -273,11 +276,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
// Build an aggregate string, and build a table of offsets into it.
StringToOffsetTable StringTable;
-
+
/// 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]];
@@ -285,7 +288,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
if (AWI == 0) {
// Something not handled by the asmwriter printer.
Idx = ~0U;
- } else if (AWI->Operands[0].OperandType !=
+ } else if (AWI->Operands[0].OperandType !=
AsmWriterOperand::isLiteralTextOperand ||
AWI->Operands[0].Str.empty()) {
// Something handled by the asmwriter printer, but with no leading string.
@@ -295,51 +298,51 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
UnescapeString(Str);
Idx = StringTable.GetOrAddStringOffset(Str);
MaxStringIdx = std::max(MaxStringIdx, Idx);
-
+
// Nuke the string from the operand list. It is now handled!
AWI->Operands.erase(AWI->Operands.begin());
}
-
+
// Bias offset by one since we want 0 as a sentinel.
OpcodeInfo.push_back(Idx+1);
}
-
+
// Figure out how many bits we used for the string index.
unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2);
-
+
// 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;
-
+
while (1) {
std::vector<std::string> UniqueOperandCommands;
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) {
DEBUG(errs() << "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))
@@ -351,13 +354,13 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
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// "
@@ -366,7 +369,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
// 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";
StringTable.EmitString(O);
@@ -388,13 +391,13 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
// 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) << ") & "
@@ -403,11 +406,14 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
<< " } else {\n"
<< Commands[0]
<< " }\n\n";
+ } else if (Commands.size() == 1) {
+ // Emit a single possibility.
+ O << 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";
@@ -417,7 +423,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
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?
@@ -428,12 +434,12 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
}
}
-
+
// 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());
-
-
+
+
// Now that we've emitted all of the operand info that fit into 32 bits, emit
// information for those instructions that are left. This is a less dense
// encoding, but we expect the main 32-bit table to handle the majority of
@@ -453,11 +459,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
-
+
StringToOffsetTable StringTable;
O <<
"\n\n/// getRegisterName - This method is automatically generated by tblgen\n"
@@ -475,33 +481,33 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
std::string AsmName = Reg.TheDef->getValueAsString("AsmName");
if (AsmName.empty())
AsmName = Reg.getName();
-
-
+
+
if ((i % 14) == 0)
O << "\n ";
-
+
O << StringTable.GetOrAddStringOffset(AsmName) << ", ";
}
O << "0\n"
<< " };\n"
<< "\n";
-
+
O << " const char *AsmStrs =\n";
StringTable.EmitString(O);
O << ";\n";
-
+
O << " return AsmStrs+RegAsmOffset[RegNo-1];\n"
<< "}\n";
}
void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
const std::vector<const CodeGenInstruction*> &NumberedInstructions =
Target.getInstructionsByEnumValue();
-
+
StringToOffsetTable StringTable;
O <<
"\n\n#ifdef GET_INSTRUCTION_NAME\n"
@@ -517,21 +523,21 @@ void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
<< " static const unsigned InstAsmOffset[] = {";
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
const CodeGenInstruction &Inst = *NumberedInstructions[i];
-
+
std::string AsmName = Inst.TheDef->getName();
if ((i % 14) == 0)
O << "\n ";
-
+
O << StringTable.GetOrAddStringOffset(AsmName) << ", ";
}
O << "0\n"
<< " };\n"
<< "\n";
-
+
O << " const char *Strs =\n";
StringTable.EmitString(O);
O << ";\n";
-
+
O << " return Strs+InstAsmOffset[Opcode];\n"
<< "}\n\n#endif\n";
}
@@ -540,7 +546,7 @@ void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
void AsmWriterEmitter::run(raw_ostream &O) {
EmitSourceFileHeader("Assembly Writer Source Fragment", O);
-
+
EmitPrintInstruction(O);
EmitGetRegisterName(O);
EmitGetInstructionName(O);
diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp
index b2228b037ddd..fdf447f2aaf3 100644
--- a/utils/TableGen/AsmWriterInst.cpp
+++ b/utils/TableGen/AsmWriterInst.cpp
@@ -53,8 +53,6 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
int OperandSpacing) {
this->CGI = &CGI;
- unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #.
-
// This is the number of tabs we've seen if we're doing columnar layout.
unsigned CurColumn = 0;
@@ -62,54 +60,48 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
// 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 AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant);
std::string::size_type LastEmitted = 0;
while (LastEmitted != AsmString.size()) {
std::string::size_type DollarPos =
- AsmString.find_first_of("${|}\\", LastEmitted);
+ 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':
- // If the asm writer is not using a columnar layout, \t is not
- // magic.
- if (FirstOperandColumn == -1 || OperandSpacing == -1) {
- AddLiteralString("\\t");
- } else {
- // We recognize a tab as an operand delimeter.
- unsigned DestColumn = FirstOperandColumn +
- CurColumn++ * OperandSpacing;
- Operands.push_back(
- AsmWriterOperand(
- "O.PadToColumn(" +
- utostr(DestColumn) + ");\n",
- AsmWriterOperand::isLiteralStatementOperand));
- }
- break;
- case '"':
- AddLiteralString("\\\"");
- break;
- case '\\':
- AddLiteralString("\\\\");
- break;
- default:
- AddLiteralString(std::string(1, AsmString[LastEmitted]));
- break;
- }
- } else {
- LastEmitted = DollarPos;
- }
+ for (; LastEmitted != DollarPos; ++LastEmitted)
+ switch (AsmString[LastEmitted]) {
+ case '\n':
+ AddLiteralString("\\n");
+ break;
+ case '\t':
+ // If the asm writer is not using a columnar layout, \t is not
+ // magic.
+ if (FirstOperandColumn == -1 || OperandSpacing == -1) {
+ AddLiteralString("\\t");
+ } else {
+ // We recognize a tab as an operand delimeter.
+ unsigned DestColumn = FirstOperandColumn +
+ CurColumn++ * OperandSpacing;
+ Operands.push_back(
+ AsmWriterOperand(
+ "O.PadToColumn(" +
+ utostr(DestColumn) + ");\n",
+ AsmWriterOperand::isLiteralStatementOperand));
+ }
+ break;
+ case '"':
+ AddLiteralString("\\\"");
+ break;
+ case '\\':
+ AddLiteralString("\\\\");
+ break;
+ default:
+ AddLiteralString(std::string(1, AsmString[LastEmitted]));
+ break;
+ }
} else if (AsmString[DollarPos] == '\\') {
- if (DollarPos+1 != AsmString.size() &&
- (CurVariant == Variant || CurVariant == ~0U)) {
+ if (DollarPos+1 != AsmString.size()) {
if (AsmString[DollarPos+1] == 'n') {
AddLiteralString("\\n");
} else if (AsmString[DollarPos+1] == 't') {
@@ -137,29 +129,9 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
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("$"); // "$$" -> $
- }
+ AddLiteralString("$"); // "$$" -> $
LastEmitted = DollarPos+2;
} else {
// Get the name of the variable.
@@ -226,16 +198,12 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
Modifier));
} else {
// Otherwise, normal operand.
- unsigned OpNo = CGI.getOperandNamed(VarName);
- CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
+ unsigned OpNo = CGI.Operands.getOperandNamed(VarName);
+ CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo];
- if (CurVariant == Variant || CurVariant == ~0U) {
- unsigned MIOp = OpInfo.MIOperandNo;
- Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName,
- OpNo,
- MIOp,
- Modifier));
- }
+ unsigned MIOp = OpInfo.MIOperandNo;
+ Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName,
+ OpNo, MIOp, Modifier));
}
LastEmitted = VarEnd;
}
diff --git a/utils/TableGen/AsmWriterInst.h b/utils/TableGen/AsmWriterInst.h
index 20b8588862b7..ec7d8eb10395 100644
--- a/utils/TableGen/AsmWriterInst.h
+++ b/utils/TableGen/AsmWriterInst.h
@@ -23,51 +23,51 @@
namespace llvm {
class CodeGenInstruction;
class Record;
-
+
struct AsmWriterOperand {
enum OpType {
// Output this text surrounded by quotes to the asm.
- isLiteralTextOperand,
+ isLiteralTextOperand,
// This is the name of a routine to call to print the operand.
isMachineInstrOperand,
// Output this text verbatim to the asm writer. It is code that
// will output some text to the asm.
isLiteralStatementOperand
} OperandType;
-
+
/// Str - For isLiteralTextOperand, this IS the literal text. For
/// isMachineInstrOperand, this is the PrinterMethodName for the operand..
- /// For isLiteralStatementOperand, this is the code to insert verbatim
+ /// For isLiteralStatementOperand, this is the code to insert verbatim
/// into the asm writer.
std::string Str;
-
+
/// CGIOpNo - For isMachineInstrOperand, this is the index of the operand in
/// the CodeGenInstruction.
unsigned CGIOpNo;
-
+
/// 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(OpType op = isLiteralTextOperand):OperandType(op) {}
-
+
AsmWriterOperand(const std::string &LitStr,
OpType op = isLiteralTextOperand)
: OperandType(op), Str(LitStr) {}
-
+
AsmWriterOperand(const std::string &Printer,
unsigned _CGIOpNo,
unsigned _MIOpNo,
const std::string &Modifier,
- OpType op = isMachineInstrOperand)
+ OpType op = isMachineInstrOperand)
: OperandType(op), Str(Printer), CGIOpNo(_CGIOpNo), MIOpNo(_MIOpNo),
MiModifier(Modifier) {}
-
+
bool operator!=(const AsmWriterOperand &Other) const {
if (OperandType != Other.OperandType || Str != Other.Str) return true;
if (OperandType == isMachineInstrOperand)
@@ -77,26 +77,26 @@ namespace llvm {
bool operator==(const AsmWriterOperand &Other) const {
return !operator!=(Other);
}
-
+
/// getCode - Return the code that prints this operand.
std::string getCode() const;
};
-
+
class AsmWriterInst {
public:
std::vector<AsmWriterOperand> Operands;
const CodeGenInstruction *CGI;
-
- AsmWriterInst(const CodeGenInstruction &CGI,
+
+ AsmWriterInst(const CodeGenInstruction &CGI,
unsigned Variant,
int FirstOperandColumn,
int OperandSpacing);
-
+
/// 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
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 972989ba6232..e24314c3e0ec 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,3 +1,8 @@
+set(LLVM_REQUIRES_EH 1)
+set(LLVM_REQUIRES_RTTI 1)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_TOOLS_BINARY_DIR})
+
add_executable(tblgen
ARMDecoderEmitter.cpp
AsmMatcherEmitter.cpp
@@ -7,6 +12,7 @@ add_executable(tblgen
ClangASTNodesEmitter.cpp
ClangAttrEmitter.cpp
ClangDiagnosticsEmitter.cpp
+ ClangSACheckersEmitter.cpp
CodeEmitterGen.cpp
CodeGenDAGPatterns.cpp
CodeGenInstruction.cpp
@@ -19,6 +25,7 @@ add_executable(tblgen
DisassemblerEmitter.cpp
EDEmitter.cpp
FastISelEmitter.cpp
+ FixedLenDecoderEmitter.cpp
InstrEnumEmitter.cpp
InstrInfoEmitter.cpp
IntrinsicEmitter.cpp
@@ -27,6 +34,7 @@ add_executable(tblgen
OptParserEmitter.cpp
Record.cpp
RegisterInfoEmitter.cpp
+ StringMatcher.cpp
SubtargetEmitter.cpp
TGLexer.cpp
TGParser.cpp
@@ -37,10 +45,12 @@ add_executable(tblgen
X86RecognizableInstr.cpp
)
-target_link_libraries(tblgen LLVMSupport LLVMSystem)
+target_link_libraries(tblgen LLVMSupport)
if( MINGW )
target_link_libraries(tblgen imagehlp psapi)
endif( MINGW )
if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD AND NOT BEOS )
target_link_libraries(tblgen pthread)
endif()
+
+install(TARGETS tblgen RUNTIME DESTINATION bin)
diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp
index 7643609b8724..c51afd82a37a 100644
--- a/utils/TableGen/CallingConvEmitter.cpp
+++ b/utils/TableGen/CallingConvEmitter.cpp
@@ -26,9 +26,9 @@ void CallingConvEmitter::run(raw_ostream &O) {
// other.
for (unsigned i = 0, e = CCs.size(); i != e; ++i) {
O << "static bool " << CCs[i]->getName()
- << "(unsigned ValNo, EVT ValVT,\n"
+ << "(unsigned ValNo, MVT ValVT,\n"
<< std::string(CCs[i]->getName().size()+13, ' ')
- << "EVT LocVT, CCValAssign::LocInfo LocInfo,\n"
+ << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n"
<< std::string(CCs[i]->getName().size()+13, ' ')
<< "ISD::ArgFlagsTy ArgFlags, CCState &State);\n";
}
@@ -44,9 +44,9 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) {
Counter = 0;
O << "\n\nstatic bool " << CC->getName()
- << "(unsigned ValNo, EVT ValVT,\n"
+ << "(unsigned ValNo, MVT ValVT,\n"
<< std::string(CC->getName().size()+13, ' ')
- << "EVT LocVT, CCValAssign::LocInfo LocInfo,\n"
+ << "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.
@@ -163,12 +163,12 @@ void CallingConvEmitter::EmitAction(Record *Action,
O << Size << ", ";
else
O << "\n" << IndentStr << " State.getTarget().getTargetData()"
- "->getTypeAllocSize(LocVT.getTypeForEVT(State.getContext())), ";
+ "->getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext())), ";
if (Align)
O << Align;
else
O << "\n" << IndentStr << " State.getTarget().getTargetData()"
- "->getABITypeAlignment(LocVT.getTypeForEVT(State.getContext()))";
+ "->getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()))";
if (Action->isSubClassOf("CCAssignToStackWithShadow"))
O << ", " << getQualifiedName(Action->getValueAsDef("ShadowReg"));
O << ");\n" << IndentStr
diff --git a/utils/TableGen/ClangASTNodesEmitter.h b/utils/TableGen/ClangASTNodesEmitter.h
index abf9c9a0f164..712333bd2d25 100644
--- a/utils/TableGen/ClangASTNodesEmitter.h
+++ b/utils/TableGen/ClangASTNodesEmitter.h
@@ -57,7 +57,7 @@ class ClangASTNodesEmitter : public TableGenBackend {
public:
explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,
const std::string &S)
- : Records(R), Root(N, SMLoc()), BaseSuffix(S)
+ : Records(R), Root(N, SMLoc(), R), BaseSuffix(S)
{}
// run - Output the .inc file contents
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 8d3399a95970..27e1e027d0fa 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -19,8 +19,8 @@
using namespace llvm;
-static const std::vector<StringRef> getValueAsListOfStrings(Record &R,
- StringRef FieldName) {
+static const std::vector<StringRef>
+getValueAsListOfStrings(Record &R, StringRef FieldName) {
ListInit *List = R.getValueAsListInit(FieldName);
assert (List && "Got a null ListInit");
@@ -44,7 +44,8 @@ std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
.EndsWith("Decl *", "cast_or_null<" + std::string(type, 0, type.size()-1) +
">(GetDecl(Record[Idx++]))")
- .Case("QualType", "ReadTypeRecord(Idx++)")
+ .Case("QualType", "GetType(Record[Idx++])")
+ .Case("Expr *", "ReadSubExpr()")
.Default("Record[Idx++]");
}
@@ -54,6 +55,7 @@ std::string WritePCHRecord(StringRef type, StringRef name) {
.EndsWith("Decl *", "AddDeclRef(" + std::string(name) +
", Record);\n")
.Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n")
+ .Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
.Default("Record.push_back(" + std::string(name) + ");\n");
}
@@ -171,7 +173,8 @@ namespace {
OS << "char *" << getLowerName() << ";";
}
void writePCHReadDecls(raw_ostream &OS) const {
- OS << " std::string " << getLowerName() << "= ReadString(Record, Idx);\n";
+ OS << " std::string " << getLowerName()
+ << "= ReadString(Record, Idx);\n";
}
void writePCHReadArgs(raw_ostream &OS) const {
OS << getLowerName();
@@ -269,10 +272,10 @@ namespace {
OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n";
OS << " void *" << getLowerName() << "Ptr;\n";
OS << " if (is" << getLowerName() << "Expr)\n";
- OS << " " << getLowerName() << "Ptr = ReadExpr(DeclsCursor);\n";
+ OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n";
OS << " else\n";
OS << " " << getLowerName()
- << "Ptr = GetTypeSourceInfo(DeclsCursor, Record, Idx);\n";
+ << "Ptr = GetTypeSourceInfo(F, Record, Idx);\n";
}
void writePCHWrite(raw_ostream &OS) const {
OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n";
@@ -461,8 +464,9 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) {
for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
i != e; ++i) {
Record &R = **i;
+ const std::string &SuperName = R.getSuperClasses().back()->getName();
- OS << "class " << R.getName() << "Attr : public Attr {\n";
+ OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
std::vector<Argument*> Args;
@@ -493,7 +497,7 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) {
}
OS << " )\n";
- OS << " : Attr(attr::" << R.getName() << ", L)\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", L)\n";
for (ai = Args.begin(); ai != ae; ++ai) {
OS << " , ";
@@ -557,31 +561,58 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) {
}
}
+static void EmitAttrList(raw_ostream &OS, StringRef Class,
+ const std::vector<Record*> &AttrList) {
+ std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end();
+
+ if (i != e) {
+ // Move the end iterator back to emit the last attribute.
+ for(--e; i != e; ++i)
+ OS << Class << "(" << (*i)->getName() << ")\n";
+
+ OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n";
+ }
+}
+
void ClangAttrListEmitter::run(raw_ostream &OS) {
OS << "// This file is generated by TableGen. Do not edit.\n\n";
OS << "#ifndef LAST_ATTR\n";
OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n";
OS << "#endif\n\n";
-
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
- std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
- if (i != e) {
- // Move the end iterator back to emit the last attribute.
- for(--e; i != e; ++i)
- OS << "ATTR(" << (*i)->getName() << ")\n";
-
- OS << "LAST_ATTR(" << (*i)->getName() << ")\n\n";
+ OS << "#ifndef INHERITABLE_ATTR\n";
+ OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_INHERITABLE_ATTR\n";
+ OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ Record *InhClass = Records.getClass("InheritableAttr");
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
+ NonInhAttrs, InhAttrs;
+ for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
+ i != e; ++i) {
+ if ((*i)->isSubClassOf(InhClass))
+ InhAttrs.push_back(*i);
+ else
+ NonInhAttrs.push_back(*i);
}
+ EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
+ EmitAttrList(OS, "ATTR", NonInhAttrs);
+
OS << "#undef LAST_ATTR\n";
+ OS << "#undef INHERITABLE_ATTR\n";
+ OS << "#undef LAST_INHERITABLE_ATTR\n";
OS << "#undef ATTR\n";
}
void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edi.\n\n";
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ Record *InhClass = Records.getClass("InheritableAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
ArgRecords;
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae;
@@ -595,6 +626,8 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
for (; i != e; ++i) {
Record &R = **i;
OS << " case attr::" << R.getName() << ": {\n";
+ if (R.isSubClassOf(InhClass))
+ OS << " bool isInherited = Record[Idx++];\n";
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) {
@@ -608,6 +641,8 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
(*ri)->writePCHReadArgs(OS);
}
OS << ");\n";
+ if (R.isSubClassOf(InhClass))
+ OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
OS << " break;\n";
OS << " }\n";
}
@@ -615,6 +650,7 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
}
void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) {
+ Record *InhClass = Records.getClass("InheritableAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae;
@@ -626,9 +662,11 @@ void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) {
Record &R = **i;
OS << " case attr::" << R.getName() << ": {\n";
Args = R.getValueAsListOfDefs("Args");
- if (!Args.empty())
+ if (R.isSubClassOf(InhClass) || !Args.empty())
OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName()
<< "Attr>(A);\n";
+ if (R.isSubClassOf(InhClass))
+ OS << " Record.push_back(SA->isInherited());\n";
for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai)
createArgument(**ai, R.getName())->writePCHWrite(OS);
OS << " break;\n";
@@ -636,3 +674,21 @@ void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) {
}
OS << " }\n";
}
+
+void ClangAttrSpellingListEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
+ Record &Attr = **I;
+
+ std::vector<StringRef> Spellings = getValueAsListOfStrings(Attr, "Spellings");
+
+ for (std::vector<StringRef>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) {
+ StringRef Spelling = *I;
+ OS << ".Case(\"" << Spelling << "\", true)\n";
+ }
+ }
+
+}
diff --git a/utils/TableGen/ClangAttrEmitter.h b/utils/TableGen/ClangAttrEmitter.h
index 83149824b2e7..af870098a842 100644
--- a/utils/TableGen/ClangAttrEmitter.h
+++ b/utils/TableGen/ClangAttrEmitter.h
@@ -83,6 +83,19 @@ public:
void run(raw_ostream &OS);
};
+/// ClangAttrSpellingListEmitter - class emits the list of spellings for attributes for
+/// clang.
+class ClangAttrSpellingListEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrSpellingListEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
}
#endif
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 75b6252c4f9f..60e67c467466 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -29,9 +29,10 @@ using namespace llvm;
namespace {
class DiagGroupParentMap {
+ RecordKeeper &Records;
std::map<const Record*, std::vector<Record*> > Mapping;
public:
- DiagGroupParentMap() {
+ DiagGroupParentMap(RecordKeeper &records) : Records(records) {
std::vector<Record*> DiagGroups
= Records.getAllDerivedDefinitions("DiagGroup");
for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
@@ -84,11 +85,12 @@ static std::string getDiagnosticCategory(const Record *R,
namespace {
class DiagCategoryIDMap {
+ RecordKeeper &Records;
StringMap<unsigned> CategoryIDs;
std::vector<std::string> CategoryStrings;
public:
- DiagCategoryIDMap() {
- DiagGroupParentMap ParentInfo;
+ DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
+ DiagGroupParentMap ParentInfo(Records);
// The zero'th category is "".
CategoryStrings.push_back("");
@@ -138,8 +140,8 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
const std::vector<Record*> &Diags =
Records.getAllDerivedDefinitions("Diagnostic");
- DiagCategoryIDMap CategoryIDs;
- DiagGroupParentMap DGParentMap;
+ DiagCategoryIDMap CategoryIDs(Records);
+ DiagGroupParentMap DGParentMap(Records);
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record &R = *Diags[i];
@@ -168,7 +170,13 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
OS << ", true";
else
OS << ", false";
-
+
+ // Access control bit
+ if (R.getValueAsBit("AccessControl"))
+ OS << ", true";
+ else
+ OS << ", false";
+
// Category number.
OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
OS << ")\n";
@@ -179,15 +187,17 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
// Warning Group Tables generation
//===----------------------------------------------------------------------===//
+namespace {
struct GroupInfo {
std::vector<const Record*> DiagsInGroup;
std::vector<std::string> SubGroups;
unsigned IDNo;
};
+} // end anonymous namespace.
void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
// Compute a mapping from a DiagGroup to all of its parents.
- DiagGroupParentMap DGParentMap;
+ DiagGroupParentMap DGParentMap(Records);
// Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
// groups to diags in the group.
@@ -277,7 +287,7 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
OS << "#endif // GET_DIAG_TABLE\n\n";
// Emit the category table next.
- DiagCategoryIDMap CategoriesByID;
+ DiagCategoryIDMap CategoriesByID(Records);
OS << "\n#ifdef GET_CATEGORY_TABLE\n";
for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
E = CategoriesByID.end(); I != E; ++I)
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
new file mode 100644
index 000000000000..3e49ab138fcd
--- /dev/null
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -0,0 +1,229 @@
+//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- 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 Clang Static Analyzer checkers tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckersEmitter.h"
+#include "Record.h"
+#include "llvm/ADT/DenseSet.h"
+#include <map>
+#include <string>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Static Analyzer Checkers Tables generation
+//===----------------------------------------------------------------------===//
+
+/// \brief True if it is specified hidden or a parent package is specified
+/// as hidden, otherwise false.
+static bool isHidden(const Record &R) {
+ if (R.getValueAsBit("Hidden"))
+ return true;
+ // Not declared as hidden, check the parent package if it is hidden.
+ if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage")))
+ return isHidden(*DI->getDef());
+
+ return false;
+}
+
+static bool isCheckerNamed(const Record *R) {
+ return !R->getValueAsString("CheckerName").empty();
+}
+
+static std::string getPackageFullName(const Record *R);
+
+static std::string getParentPackageFullName(const Record *R) {
+ std::string name;
+ if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ name = getPackageFullName(DI->getDef());
+ return name;
+}
+
+static std::string getPackageFullName(const Record *R) {
+ std::string name = getParentPackageFullName(R);
+ if (!name.empty()) name += ".";
+ return name + R->getValueAsString("PackageName");
+}
+
+static std::string getCheckerFullName(const Record *R) {
+ std::string name = getParentPackageFullName(R);
+ if (isCheckerNamed(R)) {
+ if (!name.empty()) name += ".";
+ name += R->getValueAsString("CheckerName");
+ }
+ return name;
+}
+
+static std::string getStringValue(const Record &R, StringRef field) {
+ if (StringInit *
+ SI = dynamic_cast<StringInit*>(R.getValueInit(field)))
+ return SI->getValue();
+ return std::string();
+}
+
+namespace {
+struct GroupInfo {
+ std::vector<const Record*> Checkers;
+ llvm::DenseSet<const Record *> SubGroups;
+ bool Hidden;
+ unsigned Index;
+
+ GroupInfo() : Hidden(false) { }
+};
+}
+
+void ClangSACheckersEmitter::run(raw_ostream &OS) {
+ std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
+ llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i)
+ checkerRecIndexMap[checkers[i]] = i;
+
+ OS << "\n#ifdef GET_CHECKERS\n";
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
+ const Record &R = *checkers[i];
+
+ OS << "CHECKER(" << "\"";
+ std::string name;
+ if (isCheckerNamed(&R))
+ name = getCheckerFullName(&R);
+ OS.write_escaped(name) << "\", ";
+ OS << R.getName() << ", ";
+ OS << getStringValue(R, "DescFile") << ", ";
+ OS << "\"";
+ OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
+ // Hidden bit
+ if (isHidden(R))
+ OS << "true";
+ else
+ OS << "false";
+ OS << ")\n";
+ }
+ OS << "#endif // GET_CHECKERS\n\n";
+
+ // Invert the mapping of checkers to package/group into a one to many
+ // mapping of packages/groups to checkers.
+ std::map<std::string, GroupInfo> groupInfoByName;
+ llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
+
+ std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
+ for (unsigned i = 0, e = packages.size(); i != e; ++i) {
+ Record *R = packages[i];
+ std::string fullName = getPackageFullName(R);
+ if (!fullName.empty()) {
+ GroupInfo &info = groupInfoByName[fullName];
+ info.Hidden = isHidden(*R);
+ recordGroupMap[R] = &info;
+ }
+ }
+
+ std::vector<Record*>
+ checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
+ for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
+ Record *R = checkerGroups[i];
+ std::string name = R->getValueAsString("GroupName");
+ if (!name.empty()) {
+ GroupInfo &info = groupInfoByName[name];
+ recordGroupMap[R] = &info;
+ }
+ }
+
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
+ Record *R = checkers[i];
+ Record *package = 0;
+ if (DefInit *
+ DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ package = DI->getDef();
+ if (!isCheckerNamed(R) && !package)
+ throw "Checker '" + R->getName() + "' is neither named, nor in a package!";
+
+ if (isCheckerNamed(R)) {
+ // Create a pseudo-group to hold this checker.
+ std::string fullName = getCheckerFullName(R);
+ GroupInfo &info = groupInfoByName[fullName];
+ recordGroupMap[R] = &info;
+ info.Checkers.push_back(R);
+ } else {
+ recordGroupMap[package]->Checkers.push_back(R);
+ }
+
+ Record *currR = isCheckerNamed(R) ? R : package;
+ // Insert the checker and its parent packages into the subgroups set of
+ // the corresponding parent package.
+ while (DefInit *DI
+ = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) {
+ Record *parentPackage = DI->getDef();
+ recordGroupMap[parentPackage]->SubGroups.insert(currR);
+ currR = parentPackage;
+ }
+ // Insert the checker into the set of its group.
+ if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+ recordGroupMap[DI->getDef()]->Checkers.push_back(R);
+ }
+
+ unsigned index = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
+ I->second.Index = index++;
+
+ // Walk through the packages/groups/checkers emitting an array for each
+ // set of checkers and an array for each set of subpackages.
+
+ OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
+ unsigned maxLen = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
+ maxLen = std::max(maxLen, (unsigned)I->first.size());
+
+ std::vector<const Record*> &V = I->second.Checkers;
+ if (!V.empty()) {
+ OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ OS << checkerRecIndexMap[V[i]] << ", ";
+ OS << "-1 };\n";
+ }
+
+ llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
+ if (!subGroups.empty()) {
+ OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
+ for (llvm::DenseSet<const Record *>::iterator
+ I = subGroups.begin(), E = subGroups.end(); I != E; ++I) {
+ OS << recordGroupMap[*I]->Index << ", ";
+ }
+ OS << "-1 };\n";
+ }
+ }
+ OS << "#endif // GET_MEMBER_ARRAYS\n\n";
+
+ OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
+ for (std::map<std::string, GroupInfo>::iterator
+ I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
+ // Group option string.
+ OS << " { \"";
+ OS.write_escaped(I->first) << "\","
+ << std::string(maxLen-I->first.size()+1, ' ');
+
+ if (I->second.Checkers.empty())
+ OS << "0, ";
+ else
+ OS << "CheckerArray" << I->second.Index << ", ";
+
+ // Subgroups.
+ if (I->second.SubGroups.empty())
+ OS << "0, ";
+ else
+ OS << "SubPackageArray" << I->second.Index << ", ";
+
+ OS << (I->second.Hidden ? "true" : "false");
+
+ OS << " },\n";
+ }
+ OS << "#endif // GET_CHECKNAME_TABLE\n\n";
+}
diff --git a/utils/TableGen/ClangSACheckersEmitter.h b/utils/TableGen/ClangSACheckersEmitter.h
new file mode 100644
index 000000000000..6bd163547329
--- /dev/null
+++ b/utils/TableGen/ClangSACheckersEmitter.h
@@ -0,0 +1,31 @@
+//===- ClangSACheckersEmitter.h - Generate Clang SA checkers tables -*- 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 Clang Static Analyzer checkers tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANGSACHECKERS_EMITTER_H
+#define CLANGSACHECKERS_EMITTER_H
+
+#include "TableGenBackend.h"
+
+namespace llvm {
+
+class ClangSACheckersEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ explicit ClangSACheckersEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index ec702c2a5d9c..957dd19da1c2 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -17,9 +17,19 @@
#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include <map>
using namespace llvm;
+// FIXME: Somewhat hackish to use a command line option for this. There should
+// be a CodeEmitter class in the Target.td that controls this sort of thing
+// instead.
+static cl::opt<bool>
+MCEmitter("mc-emitter",
+ cl::desc("Generate CodeEmitter for use with the MC library."),
+ cl::init(false));
+
void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end();
I != E; ++I) {
@@ -42,46 +52,171 @@ void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
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();
+ BitsInit *BI, int bit) {
+ if (VarBitInit *VBI = dynamic_cast<VarBitInit*>(BI->getBit(bit)))
+ if (VarInit *VI = dynamic_cast<VarInit*>(VBI->getVariable()))
+ if (VI->getName() == VarName)
+ return VBI->getBitNum();
+
+ return -1;
+}
+
+void CodeEmitterGen::
+AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
+ unsigned &NumberedOp,
+ std::string &Case, CodeGenTarget &Target) {
+ CodeGenInstruction &CGI = Target.getInstruction(R);
+
+ // Determine if VarName actually contributes to the Inst encoding.
+ int bit = BI->getNumBits()-1;
+
+ // Scan for a bit that this contributed to.
+ for (; bit >= 0; ) {
+ if (getVariableBit(VarName, BI, bit) != -1)
+ break;
- if (VarInit *VI = dynamic_cast<VarInit*>(TI)) {
- if (VI->getName() == VarName) return VBI->getBitNum();
+ --bit;
+ }
+
+ // If we found no bits, ignore this value, otherwise emit the call to get the
+ // operand encoding.
+ if (bit < 0) return;
+
+ // If the operand matches by name, reference according to that
+ // operand number. Non-matching operands are assumed to be in
+ // order.
+ unsigned OpIdx;
+ if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
+ // Get the machine operand number for the indicated operand.
+ OpIdx = CGI.Operands[OpIdx].MIOperandNo;
+ assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
+ "Explicitly used operand also marked as not emitted!");
+ } else {
+ /// If this operand is not supposed to be emitted by the
+ /// generated emitter, skip it.
+ while (CGI.Operands.isFlatOperandNotEmitted(NumberedOp))
+ ++NumberedOp;
+ OpIdx = NumberedOp++;
+ }
+
+ std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
+ std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;
+
+ // If the source operand has a custom encoder, use it. This will
+ // get the encoding for all of the suboperands.
+ if (!EncoderMethodName.empty()) {
+ // A custom encoder has all of the information for the
+ // sub-operands, if there are more than one, so only
+ // query the encoder once per source operand.
+ if (SO.second == 0) {
+ Case += " // op: " + VarName + "\n" +
+ " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
+ if (MCEmitter)
+ Case += ", Fixups";
+ Case += ");\n";
}
+ } else {
+ Case += " // op: " + VarName + "\n" +
+ " op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
+ if (MCEmitter)
+ Case += ", Fixups";
+ Case += ");\n";
}
- return -1;
-}
+ for (; bit >= 0; ) {
+ int varBit = getVariableBit(VarName, BI, bit);
+
+ // If this bit isn't from a variable, skip it.
+ if (varBit == -1) {
+ --bit;
+ continue;
+ }
+
+ // Figure out the consecutive range of bits covered by this operand, in
+ // order to generate better encoding code.
+ 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;
+ }
+
+ 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::string CodeEmitterGen::getInstructionCase(Record *R,
+ CodeGenTarget &Target) {
+ std::string Case;
+
+ BitsInit *BI = R->getValueAsBitsInit("Inst");
+ const std::vector<RecordVal> &Vals = R->getValues();
+ unsigned NumberedOp = 0;
+
+ // Loop over all of the fields in the instruction, determining which are the
+ // operands to the instruction.
+ for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
+ // Ignore fixed fields in the record, we're looking for values like:
+ // bits<5> RST = { ?, ?, ?, ?, ? };
+ if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete())
+ continue;
+
+ AddCodeToMergeInOperand(R, BI, Vals[i].getName(), NumberedOp, Case, Target);
+ }
+
+ std::string PostEmitter = R->getValueAsString("PostEncoderMethod");
+ if (!PostEmitter.empty())
+ Case += " Value = " + PostEmitter + "(MI, Value);\n";
+
+ return Case;
+}
+
void CodeEmitterGen::run(raw_ostream &o) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
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") + "::";
-
+
const std::vector<const CodeGenInstruction*> &NumberedInstructions =
Target.getInstructionsByEnumValue();
// Emit function declaration
- o << "unsigned " << Target.getName() << "CodeEmitter::"
- << "getBinaryCodeForInstr(const MachineInstr &MI) {\n";
+ o << "unsigned " << Target.getName();
+ if (MCEmitter)
+ o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
+ << " SmallVectorImpl<MCFixup> &Fixups) const {\n";
+ else
+ o << "CodeEmitter::getBinaryCodeForInstr(const MachineInstr &MI) const {\n";
// Emit instruction base values
o << " static const unsigned InstBits[] = {\n";
@@ -91,109 +226,45 @@ void CodeEmitterGen::run(raw_ostream &o) {
IN != EN; ++IN) {
const CodeGenInstruction *CGI = *IN;
Record *R = CGI->TheDef;
-
+
if (R->getValueAsString("Namespace") == "TargetOpcode") {
o << " 0U,\n";
continue;
}
-
+
BitsInit *BI = R->getValueAsBitsInit("Inst");
- // Start by filling in fixed values...
+ // 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))) {
+ 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;
if (R->getValueAsString("Namespace") == "TargetOpcode")
continue;
- const std::string &InstName = R->getName();
- std::string Case("");
-
- BitsInit *BI = R->getValueAsBitsInit("Inst");
- const std::vector<RecordVal> &Vals = R->getValues();
- CodeGenInstruction &CGI = Target.getInstruction(R);
-
- // 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";
- }
- }
- }
- }
- }
+ const std::string &InstName = R->getValueAsString("Namespace") + "::"
+ + R->getName();
+ std::string Case = getInstructionCase(R, Target);
- std::vector<std::string> &InstList = CaseMap[Case];
- InstList.push_back(InstName);
+ CaseMap[Case].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"
+ << " (void)op; // suppress warning\n"
<< " switch (opcode) {\n";
// Emit each case statement
@@ -204,7 +275,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
for (int i = 0, N = InstList.size(); i < N; i++) {
if (i) o << "\n";
- o << " case " << Namespace << InstList[i] << ":";
+ o << " case " << InstList[i] << ":";
}
o << " {\n";
o << Case;
diff --git a/utils/TableGen/CodeEmitterGen.h b/utils/TableGen/CodeEmitterGen.h
index f0b3229c0411..a874d970feac 100644
--- a/utils/TableGen/CodeEmitterGen.h
+++ b/utils/TableGen/CodeEmitterGen.h
@@ -15,7 +15,6 @@
#define CODEMITTERGEN_H
#include "TableGenBackend.h"
-#include <map>
#include <vector>
#include <string>
@@ -23,6 +22,7 @@ namespace llvm {
class RecordVal;
class BitsInit;
+class CodeGenTarget;
class CodeEmitterGen : public TableGenBackend {
RecordKeeper &Records;
@@ -36,6 +36,12 @@ private:
void emitGetValueBit(raw_ostream &o, const std::string &Namespace);
void reverseBits(std::vector<Record*> &Insts);
int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
+ std::string getInstructionCase(Record *R, CodeGenTarget &Target);
+ void
+ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
+ unsigned &NumberedOp,
+ std::string &Case, CodeGenTarget &Target);
+
};
} // End llvm namespace
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index 303aa6c450c2..aa60f871bff5 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -56,11 +56,11 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) {
EEVT::TypeSet::TypeSet(const std::vector<MVT::SimpleValueType> &VTList) {
assert(!VTList.empty() && "empty list?");
TypeVec.append(VTList.begin(), VTList.end());
-
+
if (!VTList.empty())
assert(VTList[0] != MVT::iAny && VTList[0] != MVT::vAny &&
VTList[0] != MVT::fAny);
-
+
// Verify no duplicates.
array_pod_sort(TypeVec.begin(), TypeVec.end());
assert(std::unique(TypeVec.begin(), TypeVec.end()) == TypeVec.end());
@@ -72,9 +72,9 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP,
bool (*Pred)(MVT::SimpleValueType),
const char *PredicateName) {
assert(isCompletelyUnknown());
- const std::vector<MVT::SimpleValueType> &LegalTypes =
+ const std::vector<MVT::SimpleValueType> &LegalTypes =
TP.getDAGPatterns().getTargetInfo().getLegalValueTypes();
-
+
for (unsigned i = 0, e = LegalTypes.size(); i != e; ++i)
if (Pred == 0 || Pred(LegalTypes[i]))
TypeVec.push_back(LegalTypes[i]);
@@ -82,14 +82,14 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP,
// If we have nothing that matches the predicate, bail out.
if (TypeVec.empty())
TP.error("Type inference contradiction found, no " +
- std::string(PredicateName) + " types found");
+ std::string(PredicateName) + " types found");
// No need to sort with one element.
if (TypeVec.size() == 1) return true;
// Remove duplicates.
array_pod_sort(TypeVec.begin(), TypeVec.end());
TypeVec.erase(std::unique(TypeVec.begin(), TypeVec.end()), TypeVec.end());
-
+
return true;
}
@@ -100,7 +100,7 @@ bool EEVT::TypeSet::hasIntegerTypes() const {
if (isInteger(TypeVec[i]))
return true;
return false;
-}
+}
/// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or
/// a floating point value type.
@@ -109,7 +109,7 @@ bool EEVT::TypeSet::hasFloatingPointTypes() const {
if (isFloatingPoint(TypeVec[i]))
return true;
return false;
-}
+}
/// hasVectorTypes - Return true if this TypeSet contains a vAny or a vector
/// value type.
@@ -123,9 +123,9 @@ bool EEVT::TypeSet::hasVectorTypes() const {
std::string EEVT::TypeSet::getName() const {
if (TypeVec.empty()) return "<empty>";
-
+
std::string Result;
-
+
for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) {
std::string VTName = llvm::getEnumName(TypeVec[i]);
// Strip off MVT:: prefix if present.
@@ -134,7 +134,7 @@ std::string EEVT::TypeSet::getName() const {
if (i) Result += ':';
Result += VTName;
}
-
+
if (TypeVec.size() == 1)
return Result;
return "{" + Result + "}";
@@ -146,14 +146,14 @@ std::string EEVT::TypeSet::getName() const {
bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){
if (InVT.isCompletelyUnknown() || *this == InVT)
return false;
-
+
if (isCompletelyUnknown()) {
*this = InVT;
return true;
}
-
+
assert(TypeVec.size() >= 1 && InVT.TypeVec.size() >= 1 && "No unknowns");
-
+
// Handle the abstract cases, seeing if we can resolve them better.
switch (TypeVec[0]) {
default: break;
@@ -163,26 +163,26 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){
EEVT::TypeSet InCopy(InVT);
InCopy.EnforceInteger(TP);
InCopy.EnforceScalar(TP);
-
+
if (InCopy.isConcrete()) {
// If the RHS has one integer type, upgrade iPTR to i32.
TypeVec[0] = InVT.TypeVec[0];
return true;
}
-
+
// If the input has multiple scalar integers, this doesn't add any info.
if (!InCopy.isCompletelyUnknown())
return false;
}
break;
}
-
+
// If the input constraint is iAny/iPTR and this is an integer type list,
// remove non-integer types from the list.
if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) &&
hasIntegerTypes()) {
bool MadeChange = EnforceInteger(TP);
-
+
// If we're merging in iPTR/iPTRAny and the node currently has a list of
// multiple different integer types, replace them with a single iPTR.
if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) &&
@@ -191,10 +191,10 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){
TypeVec[0] = InVT.TypeVec[0];
MadeChange = true;
}
-
+
return MadeChange;
}
-
+
// If this is a type list and the RHS is a typelist as well, eliminate entries
// from this list that aren't in the other one.
bool MadeChange = false;
@@ -207,16 +207,16 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){
InInVT = true;
break;
}
-
+
if (InInVT) continue;
TypeVec.erase(TypeVec.begin()+i--);
MadeChange = true;
}
-
+
// If we removed all of our types, we have a type contradiction.
if (!TypeVec.empty())
return MadeChange;
-
+
// FIXME: Really want an SMLoc here!
TP.error("Type inference contradiction found, merging '" +
InVT.getName() + "' into '" + InputSet.getName() + "'");
@@ -232,12 +232,12 @@ bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) {
return false;
TypeSet InputSet(*this);
-
+
// Filter out all the fp types.
for (unsigned i = 0; i != TypeVec.size(); ++i)
if (!isInteger(TypeVec[i]))
TypeVec.erase(TypeVec.begin()+i--);
-
+
if (TypeVec.empty())
TP.error("Type inference contradiction found, '" +
InputSet.getName() + "' needs to be integer");
@@ -254,12 +254,12 @@ bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) {
return false;
TypeSet InputSet(*this);
-
+
// Filter out all the fp types.
for (unsigned i = 0; i != TypeVec.size(); ++i)
if (!isFloatingPoint(TypeVec[i]))
TypeVec.erase(TypeVec.begin()+i--);
-
+
if (TypeVec.empty())
TP.error("Type inference contradiction found, '" +
InputSet.getName() + "' needs to be floating point");
@@ -276,12 +276,12 @@ bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) {
return false;
TypeSet InputSet(*this);
-
+
// Filter out all the vector types.
for (unsigned i = 0; i != TypeVec.size(); ++i)
if (!isScalar(TypeVec[i]))
TypeVec.erase(TypeVec.begin()+i--);
-
+
if (TypeVec.empty())
TP.error("Type inference contradiction found, '" +
InputSet.getName() + "' needs to be scalar");
@@ -296,14 +296,14 @@ bool EEVT::TypeSet::EnforceVector(TreePattern &TP) {
TypeSet InputSet(*this);
bool MadeChange = false;
-
+
// Filter out all the scalar types.
for (unsigned i = 0; i != TypeVec.size(); ++i)
if (!isVector(TypeVec[i])) {
TypeVec.erase(TypeVec.begin()+i--);
MadeChange = true;
}
-
+
if (TypeVec.empty())
TP.error("Type inference contradiction found, '" +
InputSet.getName() + "' needs to be a vector");
@@ -317,13 +317,13 @@ bool EEVT::TypeSet::EnforceVector(TreePattern &TP) {
bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
// Both operands must be integer or FP, but we don't care which.
bool MadeChange = false;
-
+
if (isCompletelyUnknown())
MadeChange = FillWithPossibleTypes(TP);
if (Other.isCompletelyUnknown())
MadeChange = Other.FillWithPossibleTypes(TP);
-
+
// If one side is known to be integer or known to be FP but the other side has
// no information, get at least the type integrality info in there.
if (!hasFloatingPointTypes())
@@ -334,62 +334,165 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
MadeChange |= EnforceInteger(TP);
else if (!Other.hasIntegerTypes())
MadeChange |= EnforceFloatingPoint(TP);
-
+
assert(!isCompletelyUnknown() && !Other.isCompletelyUnknown() &&
"Should have a type list now");
-
+
// If one contains vectors but the other doesn't pull vectors out.
if (!hasVectorTypes())
MadeChange |= Other.EnforceScalar(TP);
if (!hasVectorTypes())
MadeChange |= EnforceScalar(TP);
+
+ if (TypeVec.size() == 1 && Other.TypeVec.size() == 1) {
+ // If we are down to concrete types, 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(!(hasIntegerTypes() && hasFloatingPointTypes()) &&
+ !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) &&
+ "SDTCisOpSmallerThanOp does not handle mixed int/fp types!");
+
+ // Otherwise, if these are both vector types, either this vector
+ // must have a larger bitsize than the other, or this element type
+ // must be larger than the other.
+ EVT Type(TypeVec[0]);
+ EVT OtherType(Other.TypeVec[0]);
+
+ if (hasVectorTypes() && Other.hasVectorTypes()) {
+ if (Type.getSizeInBits() >= OtherType.getSizeInBits())
+ if (Type.getVectorElementType().getSizeInBits()
+ >= OtherType.getVectorElementType().getSizeInBits())
+ TP.error("Type inference contradiction found, '" +
+ getName() + "' element type not smaller than '" +
+ Other.getName() +"'!");
+ }
+ else
+ // For scalar types, the bitsize of this type must be larger
+ // than that of the other.
+ if (Type.getSizeInBits() >= OtherType.getSizeInBits())
+ TP.error("Type inference contradiction found, '" +
+ getName() + "' is not smaller than '" +
+ Other.getName() +"'!");
+
+ }
- // 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(!(hasIntegerTypes() && hasFloatingPointTypes()) &&
- !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) &&
- "SDTCisOpSmallerThanOp does not handle mixed int/fp types!");
-
+
+ // Handle int and fp as disjoint sets. This won't work for patterns
+ // that have mixed fp/int types but those are likely rare and would
+ // not have been accepted by this code previously.
+
// Okay, find the smallest type from the current set and remove it from the
// largest set.
- MVT::SimpleValueType Smallest = TypeVec[0];
+ MVT::SimpleValueType SmallestInt = MVT::LAST_VALUETYPE;
+ for (unsigned i = 0, e = TypeVec.size(); i != e; ++i)
+ if (isInteger(TypeVec[i])) {
+ SmallestInt = TypeVec[i];
+ break;
+ }
for (unsigned i = 1, e = TypeVec.size(); i != e; ++i)
- if (TypeVec[i] < Smallest)
- Smallest = TypeVec[i];
-
+ if (isInteger(TypeVec[i]) && TypeVec[i] < SmallestInt)
+ SmallestInt = TypeVec[i];
+
+ MVT::SimpleValueType SmallestFP = MVT::LAST_VALUETYPE;
+ for (unsigned i = 0, e = TypeVec.size(); i != e; ++i)
+ if (isFloatingPoint(TypeVec[i])) {
+ SmallestFP = TypeVec[i];
+ break;
+ }
+ for (unsigned i = 1, e = TypeVec.size(); i != e; ++i)
+ if (isFloatingPoint(TypeVec[i]) && TypeVec[i] < SmallestFP)
+ SmallestFP = TypeVec[i];
+
+ int OtherIntSize = 0;
+ int OtherFPSize = 0;
+ for (SmallVector<MVT::SimpleValueType, 2>::iterator TVI =
+ Other.TypeVec.begin();
+ TVI != Other.TypeVec.end();
+ /* NULL */) {
+ if (isInteger(*TVI)) {
+ ++OtherIntSize;
+ if (*TVI == SmallestInt) {
+ TVI = Other.TypeVec.erase(TVI);
+ --OtherIntSize;
+ MadeChange = true;
+ continue;
+ }
+ }
+ else if (isFloatingPoint(*TVI)) {
+ ++OtherFPSize;
+ if (*TVI == SmallestFP) {
+ TVI = Other.TypeVec.erase(TVI);
+ --OtherFPSize;
+ MadeChange = true;
+ continue;
+ }
+ }
+ ++TVI;
+ }
+
// If this is the only type in the large set, the constraint can never be
// satisfied.
- if (Other.TypeVec.size() == 1 && Other.TypeVec[0] == Smallest)
+ if ((Other.hasIntegerTypes() && OtherIntSize == 0)
+ || (Other.hasFloatingPointTypes() && OtherFPSize == 0))
TP.error("Type inference contradiction found, '" +
Other.getName() + "' has nothing larger than '" + getName() +"'!");
-
- SmallVector<MVT::SimpleValueType, 2>::iterator TVI =
- std::find(Other.TypeVec.begin(), Other.TypeVec.end(), Smallest);
- if (TVI != Other.TypeVec.end()) {
- Other.TypeVec.erase(TVI);
- MadeChange = true;
- }
-
+
// Okay, find the largest type in the Other set and remove it from the
// current set.
- MVT::SimpleValueType Largest = Other.TypeVec[0];
+ MVT::SimpleValueType LargestInt = MVT::Other;
+ for (unsigned i = 0, e = Other.TypeVec.size(); i != e; ++i)
+ if (isInteger(Other.TypeVec[i])) {
+ LargestInt = Other.TypeVec[i];
+ break;
+ }
for (unsigned i = 1, e = Other.TypeVec.size(); i != e; ++i)
- if (Other.TypeVec[i] > Largest)
- Largest = Other.TypeVec[i];
-
+ if (isInteger(Other.TypeVec[i]) && Other.TypeVec[i] > LargestInt)
+ LargestInt = Other.TypeVec[i];
+
+ MVT::SimpleValueType LargestFP = MVT::Other;
+ for (unsigned i = 0, e = Other.TypeVec.size(); i != e; ++i)
+ if (isFloatingPoint(Other.TypeVec[i])) {
+ LargestFP = Other.TypeVec[i];
+ break;
+ }
+ for (unsigned i = 1, e = Other.TypeVec.size(); i != e; ++i)
+ if (isFloatingPoint(Other.TypeVec[i]) && Other.TypeVec[i] > LargestFP)
+ LargestFP = Other.TypeVec[i];
+
+ int IntSize = 0;
+ int FPSize = 0;
+ for (SmallVector<MVT::SimpleValueType, 2>::iterator TVI =
+ TypeVec.begin();
+ TVI != TypeVec.end();
+ /* NULL */) {
+ if (isInteger(*TVI)) {
+ ++IntSize;
+ if (*TVI == LargestInt) {
+ TVI = TypeVec.erase(TVI);
+ --IntSize;
+ MadeChange = true;
+ continue;
+ }
+ }
+ else if (isFloatingPoint(*TVI)) {
+ ++FPSize;
+ if (*TVI == LargestFP) {
+ TVI = TypeVec.erase(TVI);
+ --FPSize;
+ MadeChange = true;
+ continue;
+ }
+ }
+ ++TVI;
+ }
+
// If this is the only type in the small set, the constraint can never be
// satisfied.
- if (TypeVec.size() == 1 && TypeVec[0] == Largest)
+ if ((hasIntegerTypes() && IntSize == 0)
+ || (hasFloatingPointTypes() && FPSize == 0))
TP.error("Type inference contradiction found, '" +
getName() + "' has nothing smaller than '" + Other.getName()+"'!");
-
- TVI = std::find(TypeVec.begin(), TypeVec.end(), Largest);
- if (TVI != TypeVec.end()) {
- TypeVec.erase(TVI);
- MadeChange = true;
- }
-
+
return MadeChange;
}
@@ -406,7 +509,7 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand,
if (isConcrete()) {
EVT IVT = getConcrete();
IVT = IVT.getVectorElementType();
- return MadeChange |
+ return MadeChange |
VTOperand.MergeInTypeInfo(IVT.getSimpleVT().SimpleTy, TP);
}
@@ -414,11 +517,11 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand,
// disagree.
if (!VTOperand.isConcrete())
return MadeChange;
-
+
MVT::SimpleValueType VT = VTOperand.getConcrete();
-
+
TypeSet InputSet(*this);
-
+
// Filter out all the types which don't have the right element type.
for (unsigned i = 0; i != TypeVec.size(); ++i) {
assert(isVector(TypeVec[i]) && "EnforceVector didn't work");
@@ -427,13 +530,43 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand,
MadeChange = true;
}
}
-
+
if (TypeVec.empty()) // FIXME: Really want an SMLoc here!
TP.error("Type inference contradiction found, forcing '" +
InputSet.getName() + "' to have a vector element");
return MadeChange;
}
+/// EnforceVectorSubVectorTypeIs - 'this' is now constrainted to be a
+/// vector type specified by VTOperand.
+bool EEVT::TypeSet::EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VTOperand,
+ TreePattern &TP) {
+ // "This" must be a vector and "VTOperand" must be a vector.
+ bool MadeChange = false;
+ MadeChange |= EnforceVector(TP);
+ MadeChange |= VTOperand.EnforceVector(TP);
+
+ // "This" must be larger than "VTOperand."
+ MadeChange |= VTOperand.EnforceSmallerThan(*this, TP);
+
+ // If we know the vector type, it forces the scalar types to agree.
+ if (isConcrete()) {
+ EVT IVT = getConcrete();
+ IVT = IVT.getVectorElementType();
+
+ EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP);
+ MadeChange |= VTOperand.EnforceVectorEltTypeIs(EltTypeSet, TP);
+ } else if (VTOperand.isConcrete()) {
+ EVT IVT = VTOperand.getConcrete();
+ IVT = IVT.getVectorElementType();
+
+ EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP);
+ MadeChange |= EnforceVectorEltTypeIs(EltTypeSet, TP);
+ }
+
+ return MadeChange;
+}
+
//===----------------------------------------------------------------------===//
// Helpers for working with extended types.
@@ -473,18 +606,21 @@ void FindDepVars(TreePatternNode *N, MultipleUseVarSet &DepVars) {
}
//! Dump the dependent variable set:
+#ifndef NDEBUG
void DumpDepVars(MultipleUseVarSet &DepVars) {
if (DepVars.empty()) {
DEBUG(errs() << "<empty set>");
} else {
DEBUG(errs() << "[ ");
- for (MultipleUseVarSet::const_iterator i = DepVars.begin(), e = DepVars.end();
- i != e; ++i) {
+ for (MultipleUseVarSet::const_iterator i = DepVars.begin(),
+ e = DepVars.end(); i != e; ++i) {
DEBUG(errs() << (*i) << " ");
}
DEBUG(errs() << "]");
}
}
+#endif
+
}
//===----------------------------------------------------------------------===//
@@ -502,7 +638,7 @@ static unsigned getPatternSize(const TreePatternNode *P,
// 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)
@@ -511,12 +647,12 @@ static unsigned getPatternSize(const TreePatternNode *P,
const ComplexPattern *AM = P->getComplexPatternInfo(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);
@@ -524,7 +660,7 @@ static unsigned getPatternSize(const TreePatternNode *P,
Child->getType(0) != MVT::Other)
Size += getPatternSize(Child, CGP);
else if (Child->isLeaf()) {
- if (dynamic_cast<IntInit*>(Child->getLeafValue()))
+ if (dynamic_cast<IntInit*>(Child->getLeafValue()))
Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
else if (Child->getComplexPatternInfo(CGP))
Size += getPatternSize(Child, CGP);
@@ -532,7 +668,7 @@ static unsigned getPatternSize(const TreePatternNode *P,
++Size;
}
}
-
+
return Size;
}
@@ -573,13 +709,13 @@ std::string PatternToMatch::getPredicateCheck() const {
SDTypeConstraint::SDTypeConstraint(Record *R) {
OperandNo = R->getValueAsInt("OperandNum");
-
+
if (R->isSubClassOf("SDTCisVT")) {
ConstraintType = SDTCisVT;
x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT"));
if (x.SDTCisVT_Info.VT == MVT::isVoid)
throw TGError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT");
-
+
} else if (R->isSubClassOf("SDTCisPtrTy")) {
ConstraintType = SDTCisPtrTy;
} else if (R->isSubClassOf("SDTCisInt")) {
@@ -593,15 +729,19 @@ SDTypeConstraint::SDTypeConstraint(Record *R) {
x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum");
} else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) {
ConstraintType = SDTCisVTSmallerThanOp;
- x.SDTCisVTSmallerThanOp_Info.OtherOperandNum =
+ x.SDTCisVTSmallerThanOp_Info.OtherOperandNum =
R->getValueAsInt("OtherOperandNum");
} else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) {
ConstraintType = SDTCisOpSmallerThanOp;
- x.SDTCisOpSmallerThanOp_Info.BigOperandNum =
+ x.SDTCisOpSmallerThanOp_Info.BigOperandNum =
R->getValueAsInt("BigOperandNum");
} else if (R->isSubClassOf("SDTCisEltOfVec")) {
ConstraintType = SDTCisEltOfVec;
x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum");
+ } else if (R->isSubClassOf("SDTCisSubVecOfVec")) {
+ ConstraintType = SDTCisSubVecOfVec;
+ x.SDTCisSubVecOfVec_Info.OtherOperandNum =
+ R->getValueAsInt("OtherOpNum");
} else {
errs() << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n";
exit(1);
@@ -618,11 +758,11 @@ static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N,
ResNo = OpNo;
return N;
}
-
+
OpNo -= NumResults;
-
+
if (OpNo >= N->getNumChildren()) {
- errs() << "Invalid operand number in type constraint "
+ errs() << "Invalid operand number in type constraint "
<< (OpNo+NumResults) << " ";
N->dump();
errs() << '\n';
@@ -641,7 +781,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
TreePattern &TP) const {
unsigned ResNo = 0; // The result number being referenced.
TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo);
-
+
switch (ConstraintType) {
default: assert(0 && "Unknown constraint type!");
case SDTCisVT:
@@ -676,9 +816,9 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
TP.error(N->getOperator()->getName() + " expects a VT operand!");
MVT::SimpleValueType VT =
getValueType(static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef());
-
+
EEVT::TypeSet TypeListTmp(VT, TP);
-
+
unsigned OResNo = 0;
TreePatternNode *OtherNode =
getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo,
@@ -699,13 +839,24 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
TreePatternNode *VecOperand =
getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, N, NodeInfo,
VResNo);
-
+
// Filter vector types out of VecOperand that don't have the right element
// type.
return VecOperand->getExtType(VResNo).
EnforceVectorEltTypeIs(NodeToApply->getExtType(ResNo), TP);
}
- }
+ case SDTCisSubVecOfVec: {
+ unsigned VResNo = 0;
+ TreePatternNode *BigVecOperand =
+ getOperandNum(x.SDTCisSubVecOfVec_Info.OtherOperandNum, N, NodeInfo,
+ VResNo);
+
+ // Filter vector types out of BigVecOperand that don't have the
+ // right subvector type.
+ return BigVecOperand->getExtType(VResNo).
+ EnforceVectorSubVectorTypeIs(NodeToApply->getExtType(ResNo), TP);
+ }
+ }
return false;
}
@@ -718,7 +869,7 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
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");
@@ -729,12 +880,12 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
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() == "SDNPOutGlue") {
+ Properties |= 1 << SDNPOutGlue;
+ } else if (PropList[i]->getName() == "SDNPInGlue") {
+ Properties |= 1 << SDNPInGlue;
+ } else if (PropList[i]->getName() == "SDNPOptInGlue") {
+ Properties |= 1 << SDNPOptInGlue;
} else if (PropList[i]->getName() == "SDNPMayStore") {
Properties |= 1 << SDNPMayStore;
} else if (PropList[i]->getName() == "SDNPMayLoad") {
@@ -751,8 +902,8 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
exit(1);
}
}
-
-
+
+
// Parse the type constraints.
std::vector<Record*> ConstraintList =
TypeProfile->getValueAsListOfDefs("Constraints");
@@ -767,12 +918,12 @@ MVT::SimpleValueType SDNodeInfo::getKnownType(unsigned ResNo) const {
assert(NumResults <= 1 &&
"We only work with nodes with zero or one result so far!");
assert(ResNo == 0 && "Only handles single result nodes so far");
-
+
for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i) {
// Make sure that this applies to the correct node result.
if (TypeConstraints[i].OperandNo >= NumResults) // FIXME: need value #
continue;
-
+
switch (TypeConstraints[i].ConstraintType) {
default: break;
case SDTypeConstraint::SDTCisVT:
@@ -799,20 +950,20 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) {
if (Operator->getName() == "set" ||
Operator->getName() == "implicit")
return 0; // All return nothing.
-
+
if (Operator->isSubClassOf("Intrinsic"))
return CDP.getIntrinsic(Operator).IS.RetVTs.size();
-
+
if (Operator->isSubClassOf("SDNode"))
return CDP.getSDNodeInfo(Operator).getNumResults();
-
+
if (Operator->isSubClassOf("PatFrag")) {
// If we've already parsed this pattern fragment, get it. Otherwise, handle
// the forward reference case where one pattern fragment references another
// before it is processed.
if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator))
return PFRec->getOnlyTree()->getNumTypes();
-
+
// Get the result tree.
DagInit *Tree = Operator->getValueAsDag("Fragment");
Record *Op = 0;
@@ -821,22 +972,22 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) {
assert(Op && "Invalid Fragment");
return GetNumNodeResults(Op, CDP);
}
-
+
if (Operator->isSubClassOf("Instruction")) {
CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(Operator);
// FIXME: Should allow access to all the results here.
- unsigned NumDefsToAdd = InstInfo.NumDefs ? 1 : 0;
-
+ unsigned NumDefsToAdd = InstInfo.Operands.NumDefs ? 1 : 0;
+
// Add on one implicit def if it has a resolvable type.
if (InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()) !=MVT::Other)
++NumDefsToAdd;
return NumDefsToAdd;
}
-
+
if (Operator->isSubClassOf("SDNodeXForm"))
return 1; // FIXME: Generalize SDNodeXForm
-
+
Operator->dump();
errs() << "Unhandled node in GetNumNodeResults\n";
exit(1);
@@ -862,7 +1013,7 @@ void TreePatternNode::print(raw_ostream &OS) const {
}
OS << ")";
}
-
+
for (unsigned i = 0, e = PredicateFns.size(); i != e; ++i)
OS << "<<P:" << PredicateFns[i] << ">>";
if (TransformFn)
@@ -900,7 +1051,7 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
}
return getLeafValue() == N->getLeafValue();
}
-
+
if (N->getOperator() != getOperator() ||
N->getNumChildren() != getNumChildren()) return false;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
@@ -944,7 +1095,7 @@ void TreePatternNode::RemoveAllTypes() {
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()) {
@@ -972,7 +1123,7 @@ SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) {
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) {
@@ -991,7 +1142,7 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
// 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 " +
@@ -1009,10 +1160,10 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
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());
for (unsigned i = 0, e = Types.size(); i != e; ++i)
FragTree->UpdateNodeType(i, getExtType(i), TP);
@@ -1023,7 +1174,7 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
// 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);
@@ -1038,21 +1189,21 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
// Check to see if this is a register or a register class.
if (R->isSubClassOf("RegisterClass")) {
assert(ResNo == 0 && "Regclass ref only has one result!");
- if (NotRegisters)
+ if (NotRegisters)
return EEVT::TypeSet(); // Unknown.
const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
return EEVT::TypeSet(T.getRegisterClass(R).getValueTypes());
}
-
+
if (R->isSubClassOf("PatFrag")) {
assert(ResNo == 0 && "FIXME: PatFrag with multiple results?");
// Pattern fragment types will be resolved when they are inlined.
return EEVT::TypeSet(); // Unknown.
}
-
+
if (R->isSubClassOf("Register")) {
assert(ResNo == 0 && "Registers only produce one result!");
- if (NotRegisters)
+ if (NotRegisters)
return EEVT::TypeSet(); // Unknown.
const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
return EEVT::TypeSet(T.getRegisterVTs(R));
@@ -1062,16 +1213,16 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
assert(ResNo == 0 && "SubRegisterIndices only produce one result!");
return EEVT::TypeSet();
}
-
+
if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) {
assert(ResNo == 0 && "This node only has one result!");
// Using a VTSDNode or CondCodeSDNode.
return EEVT::TypeSet(MVT::Other, TP);
}
-
+
if (R->isSubClassOf("ComplexPattern")) {
assert(ResNo == 0 && "FIXME: ComplexPattern with multiple results?");
- if (NotRegisters)
+ if (NotRegisters)
return EEVT::TypeSet(); // Unknown.
return EEVT::TypeSet(TP.getDAGPatterns().getComplexPattern(R).getValueType(),
TP);
@@ -1080,13 +1231,13 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
assert(ResNo == 0 && "Regclass can only have one result!");
return EEVT::TypeSet(MVT::iPTR, TP);
}
-
+
if (R->getName() == "node" || R->getName() == "srcvalue" ||
R->getName() == "zero_reg") {
// Placeholder.
return EEVT::TypeSet(); // Unknown.
}
-
+
TP.error("Unknown node flavor used in pattern: " + R->getName());
return EEVT::TypeSet(MVT::Other, TP);
}
@@ -1100,8 +1251,8 @@ getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const {
getOperator() != CDP.get_intrinsic_w_chain_sdnode() &&
getOperator() != CDP.get_intrinsic_wo_chain_sdnode())
return 0;
-
- unsigned IID =
+
+ unsigned IID =
dynamic_cast<IntInit*>(getChild(0)->getLeafValue())->getValue();
return &CDP.getIntrinsicInfo(IID);
}
@@ -1111,7 +1262,7 @@ getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const {
const ComplexPattern *
TreePatternNode::getComplexPatternInfo(const CodeGenDAGPatterns &CGP) const {
if (!isLeaf()) return 0;
-
+
DefInit *DI = dynamic_cast<DefInit*>(getLeafValue());
if (DI && DI->getDef()->isSubClassOf("ComplexPattern"))
return &CGP.getComplexPattern(DI->getDef());
@@ -1126,10 +1277,10 @@ bool TreePatternNode::NodeHasProperty(SDNP Property,
return CP->hasProperty(Property);
return false;
}
-
+
Record *Operator = getOperator();
if (!Operator->isSubClassOf("SDNode")) return false;
-
+
return CGP.getSDNodeInfo(Operator).hasProperty(Property);
}
@@ -1146,7 +1297,7 @@ bool TreePatternNode::TreeHasProperty(SDNP Property,
if (getChild(i)->TreeHasProperty(Property, CGP))
return true;
return false;
-}
+}
/// isCommutativeIntrinsic - Return true if the node corresponds to a
/// commutative intrinsic.
@@ -1173,27 +1324,27 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
NotRegisters, TP), TP);
return MadeChange;
}
-
+
if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) {
assert(Types.size() == 1 && "Invalid IntInit");
-
+
// Int inits are always integers. :)
bool MadeChange = Types[0].EnforceInteger(TP);
-
+
if (!Types[0].isConcrete())
return MadeChange;
-
+
MVT::SimpleValueType VT = getType(0);
if (VT == MVT::iPTR || VT == MVT::iPTRAny)
return MadeChange;
-
+
unsigned Size = EVT(VT).getSizeInBits();
// Make sure that the value is representable for this type.
if (Size >= 32) return MadeChange;
-
+
int Val = (II->getValue() << (32-Size)) >> (32-Size);
if (Val == II->getValue()) return MadeChange;
-
+
// If sign-extended doesn't fit, does it fit as unsigned?
unsigned ValueMask;
unsigned UnsignedVal;
@@ -1202,34 +1353,34 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
if ((ValueMask & UnsignedVal) == UnsignedVal)
return MadeChange;
-
+
TP.error("Integer value '" + itostr(II->getValue())+
"' is out of range for type '" + getEnumName(getType(0)) + "'!");
return MadeChange;
}
return false;
}
-
+
// special handling for set, which isn't really an SDNode.
if (getOperator()->getName() == "set") {
assert(getNumTypes() == 0 && "Set doesn't produce a value");
assert(getNumChildren() >= 2 && "Missing RHS of a set?");
unsigned NC = getNumChildren();
-
+
TreePatternNode *SetVal = getChild(NC-1);
bool MadeChange = SetVal->ApplyTypeConstraints(TP, NotRegisters);
for (unsigned i = 0; i < NC-1; ++i) {
TreePatternNode *Child = getChild(i);
MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters);
-
+
// Types of operands must match.
MadeChange |= Child->UpdateNodeType(0, SetVal->getExtType(i), TP);
MadeChange |= SetVal->UpdateNodeType(i, Child->getExtType(0), TP);
}
return MadeChange;
}
-
+
if (getOperator()->getName() == "implicit") {
assert(getNumTypes() == 0 && "Node doesn't produce a value");
@@ -1238,15 +1389,15 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
return MadeChange;
}
-
+
if (getOperator()->getName() == "COPY_TO_REGCLASS") {
bool MadeChange = false;
MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters);
-
+
assert(getChild(0)->getNumTypes() == 1 &&
getChild(1)->getNumTypes() == 1 && "Unhandled case");
-
+
// child #1 of COPY_TO_REGCLASS should be a register class. We don't care
// what type it gets, so if it didn't get a concrete type just give it the
// first viable type from the reg class.
@@ -1257,14 +1408,14 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
}
return MadeChange;
}
-
+
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(i, Int->IS.RetVTs[i], TP);
@@ -1275,46 +1426,46 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
// Apply type info to the intrinsic ID.
MadeChange |= getChild(0)->UpdateNodeType(0, MVT::iPTR, TP);
-
+
for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i) {
MadeChange |= getChild(i+1)->ApplyTypeConstraints(TP, NotRegisters);
-
+
MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i];
assert(getChild(i+1)->getNumTypes() == 1 && "Unhandled case");
MadeChange |= getChild(i+1)->UpdateNodeType(0, OpVT, TP);
}
return MadeChange;
}
-
+
if (getOperator()->isSubClassOf("SDNode")) {
const SDNodeInfo &NI = CDP.getSDNodeInfo(getOperator());
-
+
// Check that the number of operands is sane. Negative operands -> varargs.
if (NI.getNumOperands() >= 0 &&
getNumChildren() != (unsigned)NI.getNumOperands())
TP.error(getOperator()->getName() + " node requires exactly " +
itostr(NI.getNumOperands()) + " operands!");
-
+
bool MadeChange = NI.ApplyTypeConstraints(this, TP);
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
return MadeChange;
}
-
+
if (getOperator()->isSubClassOf("Instruction")) {
const DAGInstruction &Inst = CDP.getInstruction(getOperator());
CodeGenInstruction &InstInfo =
CDP.getTargetInfo().getInstruction(getOperator());
-
+
bool MadeChange = false;
// Apply the result types to the node, these come from the things in the
// (outs) list of the instruction.
// FIXME: Cap at one result so far.
- unsigned NumResultsToAdd = InstInfo.NumDefs ? 1 : 0;
+ unsigned NumResultsToAdd = InstInfo.Operands.NumDefs ? 1 : 0;
for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) {
Record *ResultNode = Inst.getResult(ResNo);
-
+
if (ResultNode->isSubClassOf("PointerLikeRegClass")) {
MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP);
} else if (ResultNode->getName() == "unknown") {
@@ -1322,26 +1473,26 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
} else {
assert(ResultNode->isSubClassOf("RegisterClass") &&
"Operands should be register classes!");
- const CodeGenRegisterClass &RC =
+ const CodeGenRegisterClass &RC =
CDP.getTargetInfo().getRegisterClass(ResultNode);
MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP);
}
}
-
+
// If the instruction has implicit defs, we apply the first one as a result.
// FIXME: This sucks, it should apply all implicit defs.
if (!InstInfo.ImplicitDefs.empty()) {
unsigned ResNo = NumResultsToAdd;
-
+
// FIXME: Generalize to multiple possible types and multiple possible
// ImplicitDefs.
MVT::SimpleValueType VT =
InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo());
-
+
if (VT != MVT::Other)
MadeChange |= UpdateNodeType(ResNo, VT, TP);
}
-
+
// If this is an INSERT_SUBREG, constrain the source and destination VTs to
// be the same.
if (getOperator()->getName() == "INSERT_SUBREG") {
@@ -1353,7 +1504,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
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.
@@ -1361,18 +1512,18 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
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++);
unsigned ChildResNo = 0; // Instructions always use res #0 of their op.
-
+
if (OperandNode->isSubClassOf("RegisterClass")) {
- const CodeGenRegisterClass &RC =
+ const CodeGenRegisterClass &RC =
CDP.getTargetInfo().getRegisterClass(OperandNode);
MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
} else if (OperandNode->isSubClassOf("Operand")) {
@@ -1392,12 +1543,12 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
if (ChildNo != getNumChildren())
TP.error("Instruction '" + getOperator()->getName() +
"' was provided too many operands!");
-
+
return MadeChange;
}
-
+
assert(getOperator()->isSubClassOf("SDNodeXForm") && "Unknown node type!");
-
+
// Node transforms always take one operand.
if (getNumChildren() != 1)
TP.error("Node transform '" + getOperator()->getName() +
@@ -1405,7 +1556,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
-
+
// 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.
@@ -1435,7 +1586,7 @@ static bool OnlyOnRHSOfCommutative(TreePatternNode *N) {
/// 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,
+bool TreePatternNode::canPatternMatch(std::string &Reason,
const CodeGenDAGPatterns &CDP) {
if (isLeaf()) return true;
@@ -1449,7 +1600,7 @@ bool TreePatternNode::canPatternMatch(std::string &Reason,
// TODO:
return true;
}
-
+
// If this node is a commutative operator, check that the LHS isn't an
// immediate.
const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(getOperator());
@@ -1466,7 +1617,7 @@ bool TreePatternNode::canPatternMatch(std::string &Reason,
}
}
}
-
+
return true;
}
@@ -1506,7 +1657,7 @@ void TreePattern::ComputeNamedNodes() {
void TreePattern::ComputeNamedNodes(TreePatternNode *N) {
if (!N->getName().empty())
NamedNodes[N->getName()].push_back(N);
-
+
for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
ComputeNamedNodes(N->getChild(i));
}
@@ -1515,7 +1666,7 @@ void TreePattern::ComputeNamedNodes(TreePatternNode *N) {
TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
if (DefInit *DI = dynamic_cast<DefInit*>(TheInit)) {
Record *R = DI->getDef();
-
+
// Direct reference to a leaf DagNode or PatFrag? Turn it into a
// TreePatternNode if its own. For example:
/// (foo GPR, imm) -> (foo GPR, (imm))
@@ -1523,7 +1674,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
return ParseTreePattern(new DagInit(DI, "",
std::vector<std::pair<Init*, std::string> >()),
OpName);
-
+
// Input argument?
TreePatternNode *Res = new TreePatternNode(DI, 1);
if (R->getName() == "node" && !OpName.empty()) {
@@ -1535,13 +1686,13 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
Res->setName(OpName);
return Res;
}
-
+
if (IntInit *II = dynamic_cast<IntInit*>(TheInit)) {
if (!OpName.empty())
error("Constant int argument should not have a name!");
return new TreePatternNode(II, 1);
}
-
+
if (BitsInit *BI = dynamic_cast<BitsInit*>(TheInit)) {
// Turn this into an IntInit.
Init *II = BI->convertInitializerTo(new IntRecTy());
@@ -1558,34 +1709,34 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
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!");
-
+
TreePatternNode *New = ParseTreePattern(Dag->getArg(0), Dag->getArgName(0));
-
+
// Apply the type cast.
assert(New->getNumTypes() == 1 && "FIXME: Unhandled");
New->UpdateNodeType(0, getValueType(Operator), *this);
-
+
if (!OpName.empty())
error("ValueType cast should not have a name!");
return New;
}
-
+
// Verify that this is something that makes sense for an operator.
- if (!Operator->isSubClassOf("PatFrag") &&
+ if (!Operator->isSubClassOf("PatFrag") &&
!Operator->isSubClassOf("SDNode") &&
- !Operator->isSubClassOf("Instruction") &&
+ !Operator->isSubClassOf("Instruction") &&
!Operator->isSubClassOf("SDNodeXForm") &&
!Operator->isSubClassOf("Intrinsic") &&
Operator->getName() != "set" &&
Operator->getName() != "implicit")
error("Unrecognized node '" + Operator->getName() + "'!");
-
+
// Check to see if this is something that is illegal in an input pattern.
if (isInputPattern) {
if (Operator->isSubClassOf("Instruction") ||
@@ -1594,7 +1745,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
} else {
if (Operator->isSubClassOf("Intrinsic"))
error("Cannot use '" + Operator->getName() + "' in an output pattern!");
-
+
if (Operator->isSubClassOf("SDNode") &&
Operator->getName() != "imm" &&
Operator->getName() != "fpimm" &&
@@ -1609,15 +1760,15 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
Operator->getName() != "vt")
error("Cannot use '" + Operator->getName() + "' in an output pattern!");
}
-
+
std::vector<TreePatternNode*> Children;
// Parse all the operands.
for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i)
Children.push_back(ParseTreePattern(Dag->getArg(i), Dag->getArgName(i)));
-
+
// If the operator is an intrinsic, then this is just syntactic sugar for for
- // (intrinsic_* <number>, ..children..). Pick the right intrinsic node, and
+ // (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);
@@ -1632,15 +1783,15 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
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), 1);
Children.insert(Children.begin(), IIDNode);
}
-
+
unsigned NumResults = GetNumNodeResults(Operator, CDP);
TreePatternNode *Result = new TreePatternNode(Operator, Children, NumResults);
Result->setName(OpName);
-
+
if (!Dag->getName().empty()) {
assert(Result->getName().empty());
Result->setName(Dag->getName());
@@ -1698,10 +1849,10 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) {
}
// If there are constraints on our named nodes, apply them.
- for (StringMap<SmallVector<TreePatternNode*,1> >::iterator
+ for (StringMap<SmallVector<TreePatternNode*,1> >::iterator
I = NamedNodes.begin(), E = NamedNodes.end(); I != E; ++I) {
SmallVectorImpl<TreePatternNode*> &Nodes = I->second;
-
+
// If we have input named node types, propagate their types to the named
// values here.
if (InNamedTypes) {
@@ -1724,7 +1875,7 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) {
if (DI && DI->getDef()->isSubClassOf("RegisterClass"))
continue;
}
-
+
assert(Nodes[i]->getNumTypes() == 1 &&
InNodes[0]->getNumTypes() == 1 &&
"FIXME: cannot name multiple result nodes yet");
@@ -1732,7 +1883,7 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) {
*this);
}
}
-
+
// If there are multiple nodes with the same name, they must all have the
// same type.
if (I->second.size() > 1) {
@@ -1740,14 +1891,14 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) {
TreePatternNode *N1 = Nodes[i], *N2 = Nodes[i+1];
assert(N1->getNumTypes() == 1 && N2->getNumTypes() == 1 &&
"FIXME: cannot name multiple result nodes yet");
-
+
MadeChange |= N1->UpdateNodeType(0, N2->getExtType(0), *this);
MadeChange |= N2->UpdateNodeType(0, N1->getExtType(0), *this);
}
}
}
}
-
+
bool HasUnresolvedTypes = false;
for (unsigned i = 0, e = Trees.size(); i != e; ++i)
HasUnresolvedTypes |= Trees[i]->ContainsUnresolvedType();
@@ -1763,7 +1914,7 @@ void TreePattern::print(raw_ostream &OS) const {
OS << ")";
}
OS << ": ";
-
+
if (Trees.size() > 1)
OS << "[\n";
for (unsigned i = 0, e = Trees.size(); i != e; ++i) {
@@ -1782,7 +1933,9 @@ void TreePattern::dump() const { print(errs()); }
// CodeGenDAGPatterns implementation
//
-CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) {
+CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) :
+ Records(R), Target(R) {
+
Intrinsics = LoadIntrinsics(Records, false);
TgtIntrinsics = LoadIntrinsics(Records, true);
ParseNodeInfo();
@@ -1792,7 +1945,7 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) {
ParseDefaultOperands();
ParseInstructions();
ParsePatterns();
-
+
// Generate variants. For example, commutative patterns can match
// multiple ways. Add them to PatternsToMatch as well.
GenerateVariants();
@@ -1863,20 +2016,20 @@ void CodeGenDAGPatterns::ParseComplexPatterns() {
///
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());
@@ -1887,8 +2040,8 @@ void CodeGenDAGPatterns::ParsePatternFragments() {
OpsOp->getDef()->getName() != "outs" &&
OpsOp->getDef()->getName() != "ins"))
P->error("Operands list should start with '(ops ... '!");
-
- // Copy over the arguments.
+
+ // Copy over the arguments.
Args.clear();
for (unsigned j = 0, e = OpsList->getNumArgs(); j != e; ++j) {
if (!dynamic_cast<DefInit*>(OpsList->getArg(j)) ||
@@ -1903,7 +2056,7 @@ void CodeGenDAGPatterns::ParsePatternFragments() {
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() + "'!");
@@ -1913,20 +2066,20 @@ void CodeGenDAGPatterns::ParsePatternFragments() {
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 {
@@ -1937,7 +2090,7 @@ void CodeGenDAGPatterns::ParsePatternFragments() {
// actually used by instructions, the type consistency error will be
// reported there.
}
-
+
// If debugging, print out the pattern fragment result.
DEBUG(ThePat->dump());
}
@@ -1951,11 +2104,11 @@ void CodeGenDAGPatterns::ParseDefaultOperands() {
// 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;
@@ -1963,20 +2116,20 @@ void CodeGenDAGPatterns::ParseDefaultOperands() {
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 '" +
@@ -2033,7 +2186,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat,
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");
@@ -2056,13 +2209,13 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
I->error("Cannot specify a transform function for a non-input value!");
return;
}
-
+
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!");
@@ -2070,7 +2223,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
}
return;
}
-
+
if (Pat->getOperator()->getName() != "set") {
// If this is not a set, verify that the children nodes are not void typed,
// and recurse.
@@ -2080,30 +2233,30 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults,
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);
-
+
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!");
@@ -2121,7 +2274,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
I->error("set destination should be a register!");
}
}
-
+
// Verify and collect info from the computation.
FindPatternInputsAndOutputs(I, Pat->getChild(NumDests),
InstInputs, InstResults, InstImpResults);
@@ -2254,8 +2407,8 @@ static void InferFromPattern(const CodeGenInstruction &Inst,
"which already inferred this.\n", Inst.TheDef->getName().c_str());
HasSideEffects = true;
}
-
- if (Inst.isVariadic)
+
+ if (Inst.Operands.isVariadic)
IsVariadic = true; // Can warn if we want.
}
@@ -2264,64 +2417,64 @@ static void InferFromPattern(const CodeGenInstruction &Inst,
/// 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]);
- if (InstInfo.OperandList.size() != 0) {
- if (InstInfo.NumDefs == 0) {
+ if (InstInfo.Operands.size() != 0) {
+ if (InstInfo.Operands.NumDefs == 0) {
// These produce no results
- for (unsigned j = 0, e = InstInfo.OperandList.size(); j < e; ++j)
- Operands.push_back(InstInfo.OperandList[j].Rec);
+ for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j)
+ Operands.push_back(InstInfo.Operands[j].Rec);
} else {
// Assume the first operand is the result.
- Results.push_back(InstInfo.OperandList[0].Rec);
-
+ Results.push_back(InstInfo.Operands[0].Rec);
+
// The rest are inputs.
- for (unsigned j = 1, e = InstInfo.OperandList.size(); j < e; ++j)
- Operands.push_back(InstInfo.OperandList[j].Rec);
+ for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j)
+ Operands.push_back(InstInfo.Operands[j].Rec);
}
}
-
+
// Create and insert the instruction.
std::vector<Record*> ImpResults;
- Instructions.insert(std::make_pair(Instrs[i],
+ Instructions.insert(std::make_pair(Instrs[i],
DAGInstruction(0, Results, Operands, ImpResults)));
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
+
+ // 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*> 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) {
@@ -2348,29 +2501,29 @@ void CodeGenDAGPatterns::ParseInstructions() {
std::vector<Record*> Results;
TreePatternNode *Res0Node = 0;
for (unsigned i = 0; i != NumResults; ++i) {
- if (i == CGI.OperandList.size())
+ if (i == CGI.Operands.size())
I->error("'" + InstResults.begin()->first +
"' set but does not appear in operand list!");
- const std::string &OpName = CGI.OperandList[i].Name;
-
+ const std::string &OpName = CGI.Operands[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)
+
+ if (CGI.Operands[i].Rec != R)
I->error("Operand $" + OpName + " class mismatch!");
-
+
// Remember the return type.
- Results.push_back(CGI.OperandList[i].Rec);
-
+ Results.push_back(CGI.Operands[i].Rec);
+
// Okay, this one checks out.
InstResults.erase(OpName);
}
@@ -2381,8 +2534,8 @@ void CodeGenDAGPatterns::ParseInstructions() {
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];
+ for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) {
+ CGIOperandList::OperandInfo &Op = CGI.Operands[i];
const std::string &OpName = Op.Name;
if (OpName.empty())
I->error("Operand #" + utostr(i) + " in operands list has no name!");
@@ -2403,7 +2556,7 @@ void CodeGenDAGPatterns::ParseInstructions() {
}
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();
@@ -2412,13 +2565,13 @@ void CodeGenDAGPatterns::ParseInstructions() {
" 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);
@@ -2426,10 +2579,10 @@ void CodeGenDAGPatterns::ParseInstructions() {
Children.push_back(OpNode);
OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes());
}
-
+
ResultNodeOperands.push_back(OpNode);
}
-
+
if (!InstInputsCheck.empty())
I->error("Input operand $" + InstInputsCheck.begin()->first +
" occurs in pattern but not in operands list!");
@@ -2454,10 +2607,10 @@ void CodeGenDAGPatterns::ParseInstructions() {
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, RecordPtrCmp>::iterator II =
Instructions.begin(),
@@ -2476,10 +2629,11 @@ void CodeGenDAGPatterns::ParseInstructions() {
// Not a set (store or something?)
SrcPattern = Pattern;
}
-
+
Record *Instr = II->first;
AddPatternToMatch(I,
- PatternToMatch(Instr->getValueAsListInit("Predicates"),
+ PatternToMatch(Instr,
+ Instr->getValueAsListInit("Predicates"),
SrcPattern,
TheInst.getResultPattern(),
TheInst.getImpResults(),
@@ -2491,7 +2645,7 @@ void CodeGenDAGPatterns::ParseInstructions() {
typedef std::pair<const TreePatternNode*, unsigned> NameRecord;
-static void FindNames(const TreePatternNode *P,
+static void FindNames(const TreePatternNode *P,
std::map<std::string, NameRecord> &Names,
const TreePattern *PatternTop) {
if (!P->getName().empty()) {
@@ -2503,7 +2657,7 @@ static void FindNames(const TreePatternNode *P,
PatternTop->error("repetition of value: $" + P->getName() +
" where different uses have different types!");
}
-
+
if (!P->isLeaf()) {
for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
FindNames(P->getChild(i), Names, PatternTop);
@@ -2516,7 +2670,7 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern,
std::string Reason;
if (!PTM.getSrcPattern()->canPatternMatch(Reason, *this))
Pattern->error("Pattern can never match: " + Reason);
-
+
// If the source pattern's root is a complex pattern, that complex pattern
// must specify the nodes it can potentially match.
if (const ComplexPattern *CP =
@@ -2524,8 +2678,8 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern,
if (CP->getRootNodes().empty())
Pattern->error("ComplexPattern at root must specify list of opcodes it"
" could match");
-
-
+
+
// Find all of the named values in the input and output, ensure they have the
// same type.
std::map<std::string, NameRecord> SrcNames, DstNames;
@@ -2540,14 +2694,14 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern,
Pattern->error("Pattern has input without matching name in output: $" +
I->first);
}
-
+
// Scan all of the named values in the source pattern, rejecting them if the
// name isn't used in the dest, and isn't used to tie two values together.
for (std::map<std::string, NameRecord>::iterator
I = SrcNames.begin(), E = SrcNames.end(); I != E; ++I)
if (DstNames[I->first].first == 0 && SrcNames[I->first].second == 1)
Pattern->error("Pattern has dead named input: $" + I->first);
-
+
PatternsToMatch.push_back(PTM);
}
@@ -2566,7 +2720,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() {
InstInfo.mayStore = MayStore;
InstInfo.mayLoad = MayLoad;
InstInfo.hasSideEffects = HasSideEffects;
- InstInfo.isVariadic = IsVariadic;
+ InstInfo.Operands.isVariadic = IsVariadic;
}
}
@@ -2576,7 +2730,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() {
static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) {
if (N->isLeaf())
return false;
-
+
// Analyze children.
for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
if (ForceArbitraryInstResultType(N->getChild(i), TP))
@@ -2590,12 +2744,12 @@ static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) {
for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i) {
if (N->getExtType(i).isCompletelyUnknown() || N->getExtType(i).isConcrete())
continue;
-
+
// Otherwise, force its type to the first possibility (an arbitrary choice).
if (N->getExtType(i).MergeInTypeInfo(N->getExtType(i).getTypeList()[0], TP))
return true;
}
-
+
return false;
}
@@ -2609,20 +2763,20 @@ void CodeGenDAGPatterns::ParsePatterns() {
// Inline pattern fragments into it.
Pattern->InlinePatternFragments();
-
+
ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs");
if (LI->getSize() == 0) continue; // no pattern.
-
+
// Parse the instruction.
TreePattern *Result = new TreePattern(CurPattern, 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 {
@@ -2630,14 +2784,14 @@ void CodeGenDAGPatterns::ParsePatterns() {
// can never do anything with this pattern: report it to the user.
InferredAllPatternTypes =
Pattern->InferAllTypes(&Pattern->getNamedNodesMap());
-
+
// 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(&Pattern->getNamedNodesMap());
IterateInference = false;
-
+
// 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
@@ -2650,7 +2804,7 @@ void CodeGenDAGPatterns::ParsePatterns() {
IterateInference |= Result->getTree(0)->
UpdateNodeType(i, Pattern->getTree(0)->getExtType(i), *Result);
}
-
+
// If our iteration has converged and the input pattern's types are fully
// resolved but the result pattern is not fully resolved, we may have a
// situation where we have two instructions in the result pattern and
@@ -2665,7 +2819,7 @@ void CodeGenDAGPatterns::ParsePatterns() {
IterateInference = ForceArbitraryInstResultType(Result->getTree(0),
*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)
@@ -2674,7 +2828,7 @@ void CodeGenDAGPatterns::ParsePatterns() {
Pattern->dump();
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;
@@ -2702,16 +2856,17 @@ void CodeGenDAGPatterns::ParsePatterns() {
DstPattern = new TreePatternNode(DstPattern->getOperator(),
ResultNodeOperands,
DstPattern->getNumTypes());
-
+
for (unsigned i = 0, e = Result->getOnlyTree()->getNumTypes(); i != e; ++i)
DstPattern->setType(i, Result->getOnlyTree()->getExtType(i));
-
+
TreePattern Temp(Result->getRecord(), DstPattern, false, *this);
Temp.InferAllTypes();
-
+
AddPatternToMatch(Pattern,
- PatternToMatch(CurPattern->getValueAsListInit("Predicates"),
+ PatternToMatch(CurPattern,
+ CurPattern->getValueAsListInit("Predicates"),
Pattern->getTree(0),
Temp.getOnlyTree(), InstImpResults,
CurPattern->getValueAsInt("AddedComplexity"),
@@ -2721,7 +2876,7 @@ void CodeGenDAGPatterns::ParsePatterns() {
/// 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,
+static void CombineChildVariants(TreePatternNode *Orig,
const std::vector<std::vector<TreePatternNode*> > &ChildVariants,
std::vector<TreePatternNode*> &OutVariants,
CodeGenDAGPatterns &CDP,
@@ -2730,7 +2885,7 @@ static void CombineChildVariants(TreePatternNode *Orig,
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());
@@ -2751,21 +2906,21 @@ static void CombineChildVariants(TreePatternNode *Orig,
NewChildren.push_back(ChildVariants[i][Idxs[i]]);
TreePatternNode *R = new TreePatternNode(Orig->getOperator(), NewChildren,
Orig->getNumTypes());
-
+
// Copy over properties.
R->setName(Orig->getName());
R->setPredicateFns(Orig->getPredicateFns());
R->setTransformFn(Orig->getTransformFn());
for (unsigned i = 0, e = Orig->getNumTypes(); i != e; ++i)
R->setType(i, Orig->getExtType(i));
-
+
// 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)
@@ -2775,13 +2930,13 @@ static void CombineChildVariants(TreePatternNode *Orig,
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].
@@ -2798,7 +2953,7 @@ static void CombineChildVariants(TreePatternNode *Orig,
/// CombineChildVariants - A helper function for binary operators.
///
-static void CombineChildVariants(TreePatternNode *Orig,
+static void CombineChildVariants(TreePatternNode *Orig,
const std::vector<TreePatternNode*> &LHS,
const std::vector<TreePatternNode*> &RHS,
std::vector<TreePatternNode*> &OutVariants,
@@ -2808,14 +2963,14 @@ static void CombineChildVariants(TreePatternNode *Orig,
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()) {
@@ -2852,7 +3007,7 @@ static void GenerateVariantsOf(TreePatternNode *N,
// If this node is associative, re-associate.
if (NodeInfo.hasProperty(SDNPAssociative)) {
- // Re-associate by pulling together all of the linked operators
+ // Re-associate by pulling together all of the linked operators
std::vector<TreePatternNode*> MaximalChildren;
GatherChildrenOfAssociativeOpcode(N, MaximalChildren);
@@ -2864,11 +3019,11 @@ static void GenerateVariantsOf(TreePatternNode *N,
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;
@@ -2901,7 +3056,7 @@ static void GenerateVariantsOf(TreePatternNode *N,
return;
}
}
-
+
// Compute permutations of all children.
std::vector<std::vector<TreePatternNode*> > ChildVariants;
ChildVariants.resize(N->getNumChildren());
@@ -2953,7 +3108,7 @@ static void GenerateVariantsOf(TreePatternNode *N,
// match multiple ways. Add them to PatternsToMatch as well.
void CodeGenDAGPatterns::GenerateVariants() {
DEBUG(errs() << "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
@@ -2970,7 +3125,8 @@ void CodeGenDAGPatterns::GenerateVariants() {
DEBUG(errs() << "Dependent/multiply used variables: ");
DEBUG(DumpDepVars(DepVars));
DEBUG(errs() << "\n");
- GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, DepVars);
+ GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this,
+ DepVars);
assert(!Variants.empty() && "Must create at least original variant!");
Variants.erase(Variants.begin()); // Remove the original pattern.
@@ -2988,7 +3144,7 @@ void CodeGenDAGPatterns::GenerateVariants() {
DEBUG(errs() << " VAR#" << v << ": ";
Variant->dump();
errs() << "\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) {
@@ -2997,7 +3153,8 @@ void CodeGenDAGPatterns::GenerateVariants() {
PatternsToMatch[p].getPredicates())
continue;
// Check to see if this variant already exists.
- if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), DepVars)) {
+ if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(),
+ DepVars)) {
DEBUG(errs() << " *** ALREADY EXISTS, ignoring variant.\n");
AlreadyExists = true;
break;
@@ -3008,7 +3165,8 @@ void CodeGenDAGPatterns::GenerateVariants() {
// Otherwise, add it to the list of patterns we have.
PatternsToMatch.
- push_back(PatternToMatch(PatternsToMatch[i].getPredicates(),
+ push_back(PatternToMatch(PatternsToMatch[i].getSrcRecord(),
+ PatternsToMatch[i].getPredicates(),
Variant, PatternsToMatch[i].getDstPattern(),
PatternsToMatch[i].getDstRegs(),
PatternsToMatch[i].getAddedComplexity(),
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 0a1362ab2494..946dceed66c0 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -58,50 +58,50 @@ namespace EEVT {
public:
TypeSet() {}
TypeSet(MVT::SimpleValueType VT, TreePattern &TP);
- TypeSet(const std::vector<MVT::SimpleValueType> &VTList);
-
+ TypeSet(const std::vector<MVT::SimpleValueType> &VTList);
+
bool isCompletelyUnknown() const { return TypeVec.empty(); }
-
+
bool isConcrete() const {
if (TypeVec.size() != 1) return false;
unsigned char T = TypeVec[0]; (void)T;
assert(T < MVT::LAST_VALUETYPE || T == MVT::iPTR || T == MVT::iPTRAny);
return true;
}
-
+
MVT::SimpleValueType getConcrete() const {
assert(isConcrete() && "Type isn't concrete yet");
return (MVT::SimpleValueType)TypeVec[0];
}
-
+
bool isDynamicallyResolved() const {
return getConcrete() == MVT::iPTR || getConcrete() == MVT::iPTRAny;
}
-
+
const SmallVectorImpl<MVT::SimpleValueType> &getTypeList() const {
assert(!TypeVec.empty() && "Not a type list!");
return TypeVec;
}
-
+
bool isVoid() const {
return TypeVec.size() == 1 && TypeVec[0] == MVT::isVoid;
}
-
+
/// hasIntegerTypes - Return true if this TypeSet contains any integer value
/// types.
bool hasIntegerTypes() const;
-
+
/// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or
/// a floating point value type.
bool hasFloatingPointTypes() const;
-
+
/// hasVectorTypes - Return true if this TypeSet contains a vector value
/// type.
bool hasVectorTypes() const;
-
+
/// getName() - Return this TypeSet as a string.
std::string getName() const;
-
+
/// MergeInTypeInfo - This merges in type information from the specified
/// argument. If 'this' changes, it returns true. If the two types are
/// contradictory (e.g. merge f32 into i32) then this throws an exception.
@@ -126,14 +126,18 @@ namespace EEVT {
/// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update
/// this an other based on this information.
bool EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP);
-
+
/// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type
/// whose element is VT.
bool EnforceVectorEltTypeIs(EEVT::TypeSet &VT, TreePattern &TP);
-
+
+ /// EnforceVectorSubVectorTypeIs - 'this' is now constrainted to
+ /// be a vector type VT.
+ bool EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VT, TreePattern &TP);
+
bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; }
bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; }
-
+
private:
/// FillWithPossibleTypes - Set to all legal types and return true, only
/// valid on completely unknown type sets. If Pred is non-null, only MVTs
@@ -151,13 +155,14 @@ typedef std::set<std::string> MultipleUseVarSet;
/// 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, SDTCisVec, SDTCisSameAs,
- SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec
+ enum {
+ SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs,
+ SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec,
+ SDTCisSubVecOfVec
} ConstraintType;
-
+
union { // The discriminated union.
struct {
MVT::SimpleValueType VT;
@@ -174,6 +179,9 @@ struct SDTypeConstraint {
struct {
unsigned OtherOperandNum;
} SDTCisEltOfVec_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisSubVecOfVec_Info;
} x;
/// ApplyTypeConstraint - Given a node in a pattern, apply this type
@@ -197,25 +205,25 @@ class SDNodeInfo {
std::vector<SDTypeConstraint> TypeConstraints;
public:
SDNodeInfo(Record *R); // Parse the specified record.
-
+
unsigned getNumResults() const { return NumResults; }
-
+
/// getNumOperands - This is the number of operands required or -1 if
/// variadic.
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;
}
-
+
/// getKnownType - If the type constraints on this node imply a fixed type
/// (e.g. all stores return void, etc), then return it as an
/// MVT::SimpleValueType. Otherwise, return MVT::Other.
MVT::SimpleValueType getKnownType(unsigned ResNo) const;
-
+
/// hasProperty - Return true if this node has the specified property.
///
bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }
@@ -240,31 +248,31 @@ class TreePatternNode {
/// result may be a set of possible types. After (successful) type inference,
/// each is a single concrete type.
SmallVector<EEVT::TypeSet, 1> 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,
- unsigned NumResults)
+ unsigned NumResults)
: Operator(Op), Val(0), TransformFn(0), Children(Ch) {
Types.resize(NumResults);
}
@@ -273,12 +281,12 @@ public:
Types.resize(NumResults);
}
~TreePatternNode();
-
+
const std::string &getName() const { return Name; }
void setName(StringRef N) { Name.assign(N.begin(), N.end()); }
-
+
bool isLeaf() const { return Val != 0; }
-
+
// Type accessors.
unsigned getNumTypes() const { return Types.size(); }
MVT::SimpleValueType getType(unsigned ResNo) const {
@@ -288,7 +296,7 @@ public:
const EEVT::TypeSet &getExtType(unsigned ResNo) const { return Types[ResNo]; }
EEVT::TypeSet &getExtType(unsigned ResNo) { return Types[ResNo]; }
void setType(unsigned ResNo, const EEVT::TypeSet &T) { Types[ResNo] = T; }
-
+
bool hasTypeSet(unsigned ResNo) const {
return Types[ResNo].isConcrete();
}
@@ -298,16 +306,16 @@ public:
bool isTypeDynamicallyResolved(unsigned ResNo) const {
return Types[ResNo].isDynamicallyResolved();
}
-
+
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;
}
-
+
/// hasChild - Return true if N is any of our children.
bool hasChild(const TreePatternNode *N) const {
for (unsigned i = 0, e = Children.size(); i != e; ++i)
@@ -321,7 +329,7 @@ public:
assert(PredicateFns.empty() && "Overwriting non-empty predicate list!");
PredicateFns = Fns;
}
- void addPredicateFn(const std::string &Fn) {
+ void addPredicateFn(const std::string &Fn) {
assert(!Fn.empty() && "Empty predicate string!");
if (std::find(PredicateFns.begin(), PredicateFns.end(), Fn) ==
PredicateFns.end())
@@ -330,7 +338,7 @@ public:
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;
@@ -342,18 +350,18 @@ public:
/// NodeHasProperty - Return true if this node has the specified property.
bool NodeHasProperty(SDNP Property, const CodeGenDAGPatterns &CGP) const;
-
+
/// TreeHasProperty - Return true if any node in this tree has the specified
/// property.
bool TreeHasProperty(SDNP Property, const CodeGenDAGPatterns &CGP) const;
-
+
/// isCommutativeIntrinsic - Return true if the node is an intrinsic which is
/// marked isCommutative.
bool isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const;
-
+
void print(raw_ostream &OS) const;
void dump() const;
-
+
public: // Higher level manipulation routines.
/// clone - Return a new copy of this tree.
@@ -362,14 +370,14 @@ public: // Higher level manipulation routines.
/// RemoveAllTypes - Recursively strip all the types of this tree.
void RemoveAllTypes();
-
+
/// 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,
@@ -379,13 +387,13 @@ public: // Higher level manipulation routines.
/// 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.
@@ -399,18 +407,18 @@ public: // Higher level manipulation routines.
TreePattern &TP) {
return Types[ResNo].MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP);
}
-
+
/// ContainsUnresolvedType - Return true if this tree contains any
/// unresolved types.
bool ContainsUnresolvedType() const {
for (unsigned i = 0, e = Types.size(); i != e; ++i)
if (!Types[i].isConcrete()) 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);
@@ -420,7 +428,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const TreePatternNode &TPN) {
TPN.print(OS);
return OS;
}
-
+
/// TreePattern - Represent a pattern, used for instructions, pattern
/// fragments, etc.
@@ -430,19 +438,19 @@ class TreePattern {
/// Note that PatFrag's only have a single tree.
///
std::vector<TreePatternNode*> Trees;
-
+
/// NamedNodes - This is all of the nodes that have names in the trees in this
/// pattern.
StringMap<SmallVector<TreePatternNode*,1> > NamedNodes;
-
+
/// 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;
@@ -451,7 +459,7 @@ class TreePattern {
/// 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,
@@ -460,7 +468,7 @@ public:
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; }
@@ -470,25 +478,25 @@ public:
assert(Trees.size() == 1 && "Doesn't have exactly one pattern!");
return Trees[0];
}
-
+
const StringMap<SmallVector<TreePatternNode*,1> > &getNamedNodesMap() {
if (NamedNodes.empty())
ComputeNamedNodes();
return NamedNodes;
}
-
+
/// 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
@@ -498,20 +506,20 @@ public:
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(const StringMap<SmallVector<TreePatternNode*,1> >
*NamedTypes=0);
-
+
/// error - Throw an exception, prefixing it with information about this
/// pattern.
void error(const std::string &Msg) const;
-
+
void print(raw_ostream &OS) const;
void dump() const;
-
+
private:
TreePatternNode *ParseTreePattern(Init *DI, StringRef OpName);
void ComputeNamedNodes();
@@ -535,7 +543,7 @@ public:
const std::vector<Record*> &results,
const std::vector<Record*> &operands,
const std::vector<Record*> &impresults)
- : Pattern(TP), Results(results), Operands(operands),
+ : Pattern(TP), Results(results), Operands(operands),
ImpResults(impresults), ResultPattern(0) {}
const TreePattern *getPattern() const { return Pattern; }
@@ -543,14 +551,14 @@ public:
unsigned getNumOperands() const { return Operands.size(); }
unsigned getNumImpResults() const { return ImpResults.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];
@@ -560,21 +568,22 @@ public:
assert(RN < ImpResults.size());
return ImpResults[RN];
}
-
+
TreePatternNode *getResultPattern() const { return ResultPattern; }
};
-
+
/// PatternToMatch - Used by CodeGenDAGPatterns to keep tab of patterns
/// processed to produce isel.
class PatternToMatch {
public:
- PatternToMatch(ListInit *preds,
+ PatternToMatch(Record *srcrecord, ListInit *preds,
TreePatternNode *src, TreePatternNode *dst,
const std::vector<Record*> &dstregs,
unsigned complexity, unsigned uid)
- : Predicates(preds), SrcPattern(src), DstPattern(dst),
+ : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src), DstPattern(dst),
Dstregs(dstregs), AddedComplexity(complexity), ID(uid) {}
+ Record *SrcRecord; // Originating Record for the pattern.
ListInit *Predicates; // Top level predicate conditions to match.
TreePatternNode *SrcPattern; // Source pattern to match.
TreePatternNode *DstPattern; // Resulting pattern.
@@ -582,6 +591,7 @@ public:
unsigned AddedComplexity; // Add to matching pattern complexity.
unsigned ID; // Unique ID for the record.
+ Record *getSrcRecord() const { return SrcRecord; }
ListInit *getPredicates() const { return Predicates; }
TreePatternNode *getSrcPattern() const { return SrcPattern; }
TreePatternNode *getDstPattern() const { return DstPattern; }
@@ -589,7 +599,7 @@ public:
unsigned getAddedComplexity() const { return AddedComplexity; }
std::string getPredicateCheck() const;
-
+
/// Compute the complexity metric for the input pattern. This roughly
/// corresponds to the number of nodes that are covered.
unsigned getPatternComplexity(const CodeGenDAGPatterns &CGP) const;
@@ -599,60 +609,60 @@ public:
struct RecordPtrCmp {
bool operator()(const Record *LHS, const Record *RHS) const;
};
-
+
class CodeGenDAGPatterns {
RecordKeeper &Records;
CodeGenTarget Target;
std::vector<CodeGenIntrinsic> Intrinsics;
std::vector<CodeGenIntrinsic> TgtIntrinsics;
-
+
std::map<Record*, SDNodeInfo, RecordPtrCmp> SDNodes;
std::map<Record*, std::pair<Record*, std::string>, RecordPtrCmp> SDNodeXForms;
std::map<Record*, ComplexPattern, RecordPtrCmp> ComplexPatterns;
std::map<Record*, TreePattern*, RecordPtrCmp> PatternFragments;
std::map<Record*, DAGDefaultOperand, RecordPtrCmp> DefaultOperands;
std::map<Record*, DAGInstruction, RecordPtrCmp> 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(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, RecordPtrCmp>::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];
@@ -661,7 +671,7 @@ public:
assert(0 && "Unknown intrinsic!");
abort();
}
-
+
const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const {
if (IID-1 < Intrinsics.size())
return Intrinsics[IID-1];
@@ -670,7 +680,7 @@ public:
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;
@@ -679,12 +689,12 @@ public:
assert(0 && "Unknown intrinsic!");
abort();
}
-
+
const DAGDefaultOperand &getDefaultOperand(Record *R) const {
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!");
@@ -694,7 +704,7 @@ public:
if (!PatternFragments.count(R)) return 0;
return PatternFragments.find(R)->second;
}
-
+
typedef std::map<Record*, TreePattern*, RecordPtrCmp>::const_iterator
pf_iterator;
pf_iterator pf_begin() const { return PatternFragments.begin(); }
@@ -704,14 +714,14 @@ public:
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;
}
@@ -721,7 +731,7 @@ public:
Record *get_intrinsic_wo_chain_sdnode() const {
return intrinsic_wo_chain_sdnode;
}
-
+
bool hasTargetIntrinsics() { return !TgtIntrinsics.empty(); }
private:
@@ -734,7 +744,7 @@ private:
void ParsePatterns();
void InferInstructionFlags();
void GenerateVariants();
-
+
void AddPatternToMatch(const TreePattern *Pattern, const PatternToMatch &PTM);
void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
std::map<std::string,
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 01a1fe11f531..f37d3eabcd41 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -15,120 +15,19 @@
#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/STLExtras.h"
#include <set>
using namespace llvm;
-static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) {
- // EARLY_CLOBBER: @early $reg
- std::string::size_type wpos = CStr.find_first_of(" \t");
- std::string::size_type start = CStr.find_first_not_of(" \t");
- std::string Tok = CStr.substr(start, wpos - start);
- if (Tok == "@earlyclobber") {
- std::string Name = CStr.substr(wpos+1);
- wpos = Name.find_first_not_of(" \t");
- if (wpos == std::string::npos)
- throw "Illegal format for @earlyclobber constraint: '" + CStr + "'";
- Name = Name.substr(wpos);
- std::pair<unsigned,unsigned> Op =
- I->ParseOperandName(Name, false);
-
- // Build the string for the operand
- if (!I->OperandList[Op.first].Constraints[Op.second].isNone())
- throw "Operand '" + Name + "' cannot have multiple constraints!";
- I->OperandList[Op.first].Constraints[Op.second] =
- CodeGenInstruction::ConstraintInfo::getEarlyClobber();
- return;
- }
-
- // Only other constraint is "TIED_TO" for now.
- std::string::size_type pos = CStr.find_first_of('=');
- assert(pos != std::string::npos && "Unrecognized constraint");
- start = CStr.find_first_not_of(" \t");
- std::string Name = CStr.substr(start, pos - start);
-
- // TIED_TO: $src1 = $dst
- 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);
-
- if (!I->OperandList[DestOp.first].Constraints[DestOp.second].isNone())
- throw "Operand '" + DestOpName + "' cannot have multiple constraints!";
- I->OperandList[DestOp.first].Constraints[DestOp.second] =
- CodeGenInstruction::ConstraintInfo::getTied(FlatOpNo);
-}
-
-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 - bidx), 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");
+//===----------------------------------------------------------------------===//
+// CGIOperandList Implementation
+//===----------------------------------------------------------------------===//
- isReturn = R->getValueAsBit("isReturn");
- isBranch = R->getValueAsBit("isBranch");
- isIndirectBranch = R->getValueAsBit("isIndirectBranch");
- isCompare = R->getValueAsBit("isCompare");
- isBarrier = R->getValueAsBit("isBarrier");
- isCall = R->getValueAsBit("isCall");
- canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
- mayLoad = R->getValueAsBit("mayLoad");
- mayStore = R->getValueAsBit("mayStore");
- isPredicable = R->getValueAsBit("isPredicable");
- isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
- isCommutable = R->getValueAsBit("isCommutable");
- isTerminator = R->getValueAsBit("isTerminator");
- isReMaterializable = R->getValueAsBit("isReMaterializable");
- hasDelaySlot = R->getValueAsBit("hasDelaySlot");
- usesCustomInserter = R->getValueAsBit("usesCustomInserter");
- hasCtrlDep = R->getValueAsBit("hasCtrlDep");
- isNotDuplicable = R->getValueAsBit("isNotDuplicable");
- hasSideEffects = R->getValueAsBit("hasSideEffects");
- neverHasSideEffects = R->getValueAsBit("neverHasSideEffects");
- isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove");
- hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq");
- hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq");
+CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
+ isPredicable = false;
hasOptionalDef = false;
isVariadic = false;
- ImplicitDefs = R->getValueAsListOfDefs("Defs");
- ImplicitUses = R->getValueAsListOfDefs("Uses");
-
- if (neverHasSideEffects + hasSideEffects > 1)
- throw R->getName() + ": multiple conflicting side-effect flags set!";
DagInit *OutDI = R->getValueAsDag("OutOperandList");
@@ -137,16 +36,16 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
throw R->getName() + ": invalid def name for output list: use 'outs'";
} else
throw R->getName() + ": invalid output list: use 'outs'";
-
+
NumDefs = OutDI->getNumArgs();
-
+
DagInit *InDI = R->getValueAsDag("InOperandList");
if (DefInit *Init = dynamic_cast<DefInit*>(InDI->getOperator())) {
if (Init->getDef()->getName() != "ins")
throw R->getName() + ": invalid def name for input list: use 'ins'";
} else
throw R->getName() + ": invalid input list: use 'ins'";
-
+
unsigned MIOperandNo = 0;
std::set<std::string> OperandNames;
for (unsigned i = 0, e = InDI->getNumArgs()+OutDI->getNumArgs(); i != e; ++i){
@@ -159,25 +58,28 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
ArgInit = InDI->getArg(i-NumDefs);
ArgName = InDI->getArgName(i-NumDefs);
}
-
+
DefInit *Arg = dynamic_cast<DefInit*>(ArgInit);
if (!Arg)
throw "Illegal operand for the '" + R->getName() + "' instruction!";
Record *Rec = Arg->getDef();
std::string PrintMethod = "printOperand";
+ std::string EncoderMethod;
unsigned NumOps = 1;
DagInit *MIOpInfo = 0;
if (Rec->isSubClassOf("Operand")) {
PrintMethod = Rec->getValueAsString("PrintMethod");
+ // If there is an explicit encoder method, use it.
+ EncoderMethod = Rec->getValueAsString("EncoderMethod");
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")
+ ->getDef()->getName() != "ops")
throw "Bad value for MIOperandInfo in operand '" + Rec->getName() +
- "'\n";
+ "'\n";
// If we have MIOpInfo, then we have #operands equal to number of entries
// in MIOperandInfo.
@@ -192,58 +94,58 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
isVariadic = true;
continue;
} else if (!Rec->isSubClassOf("RegisterClass") &&
- Rec->getName() != "ptr_rc" && Rec->getName() != "unknown")
+ !Rec->isSubClassOf("PointerLikeRegClass") &&
+ Rec->getName() != "unknown")
throw "Unknown operand class '" + Rec->getName() +
- "' in '" + R->getName() + "' instruction!";
+ "' in '" + R->getName() + "' instruction!";
// Check that the operand has a name and that it's unique.
if (ArgName.empty())
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
- " has no name!";
+ " has no name!";
if (!OperandNames.insert(ArgName).second)
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
- " has the same name as a previous operand!";
+ " has the same name as a previous operand!";
- OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod,
+ OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod, EncoderMethod,
MIOperandNo, NumOps, MIOpInfo));
MIOperandNo += NumOps;
}
- // Parse Constraints.
- ParseConstraints(R->getValueAsString("Constraints"), this);
-
- // Parse the DisableEncoding field.
- std::string DisableEncoding = R->getValueAsString("DisableEncoding");
- while (1) {
- std::string OpName;
- tie(OpName, DisableEncoding) = 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;
- }
+ // 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 = OperandList.size(); i != e; ++i)
+ OperandList[i].Constraints.resize(OperandList[i].MINumOperands);
}
+
/// 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 {
+unsigned CGIOperandList::getOperandNamed(StringRef Name) const {
+ unsigned OpIdx;
+ if (hasOperandNamed(Name, OpIdx)) return OpIdx;
+ throw "'" + TheDef->getName() + "' does not have an operand named '$" +
+ Name.str() + "'!";
+}
+
+/// hasOperandNamed - Query whether the instruction has an operand of the
+/// given name. If so, return true and set OpIdx to the index of the
+/// operand. Otherwise, return false.
+bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) 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 + "'!";
+ if (OperandList[i].Name == Name) {
+ OpIdx = i;
+ return true;
+ }
+ return false;
}
std::pair<unsigned,unsigned>
-CodeGenInstruction::ParseOperandName(const std::string &Op,
- bool AllowWholeOp) {
+CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) {
if (Op.empty() || Op[0] != '$')
throw TheDef->getName() + ": Illegal operand name: '" + Op + "'";
@@ -266,7 +168,7 @@ CodeGenInstruction::ParseOperandName(const std::string &Op,
if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&
SubOpName.empty())
throw TheDef->getName() + ": Illegal to refer to"
- " whole operand part of complex operand '" + Op + "'";
+ " whole operand part of complex operand '" + Op + "'";
// Otherwise, return the operand.
return std::make_pair(OpIdx, 0U);
@@ -286,6 +188,137 @@ CodeGenInstruction::ParseOperandName(const std::string &Op,
throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
}
+static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) {
+ // EARLY_CLOBBER: @early $reg
+ std::string::size_type wpos = CStr.find_first_of(" \t");
+ std::string::size_type start = CStr.find_first_not_of(" \t");
+ std::string Tok = CStr.substr(start, wpos - start);
+ if (Tok == "@earlyclobber") {
+ std::string Name = CStr.substr(wpos+1);
+ wpos = Name.find_first_not_of(" \t");
+ if (wpos == std::string::npos)
+ throw "Illegal format for @earlyclobber constraint: '" + CStr + "'";
+ Name = Name.substr(wpos);
+ std::pair<unsigned,unsigned> Op = Ops.ParseOperandName(Name, false);
+
+ // Build the string for the operand
+ if (!Ops[Op.first].Constraints[Op.second].isNone())
+ throw "Operand '" + Name + "' cannot have multiple constraints!";
+ Ops[Op.first].Constraints[Op.second] =
+ CGIOperandList::ConstraintInfo::getEarlyClobber();
+ return;
+ }
+
+ // Only other constraint is "TIED_TO" for now.
+ std::string::size_type pos = CStr.find_first_of('=');
+ assert(pos != std::string::npos && "Unrecognized constraint");
+ start = CStr.find_first_not_of(" \t");
+ std::string Name = CStr.substr(start, pos - start);
+
+ // TIED_TO: $src1 = $dst
+ 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 = Ops.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 =
+ Ops.ParseOperandName(Name.substr(wpos), false);
+ if (SrcOp > DestOp)
+ throw "Illegal tied-to operand constraint '" + CStr + "'";
+
+
+ unsigned FlatOpNo = Ops.getFlattenedOperandNumber(SrcOp);
+
+ if (!Ops[DestOp.first].Constraints[DestOp.second].isNone())
+ throw "Operand '" + DestOpName + "' cannot have multiple constraints!";
+ Ops[DestOp.first].Constraints[DestOp.second] =
+ CGIOperandList::ConstraintInfo::getTied(FlatOpNo);
+}
+
+static void ParseConstraints(const std::string &CStr, CGIOperandList &Ops) {
+ 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 - bidx), Ops);
+ bidx = CStr.find_first_not_of(delims, eidx);
+ }
+}
+
+void CGIOperandList::ProcessDisableEncoding(std::string DisableEncoding) {
+ while (1) {
+ std::string OpName;
+ tie(OpName, DisableEncoding) = 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;
+ }
+
+}
+
+//===----------------------------------------------------------------------===//
+// CodeGenInstruction Implementation
+//===----------------------------------------------------------------------===//
+
+CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) {
+ Namespace = R->getValueAsString("Namespace");
+ AsmString = R->getValueAsString("AsmString");
+
+ isReturn = R->getValueAsBit("isReturn");
+ isBranch = R->getValueAsBit("isBranch");
+ isIndirectBranch = R->getValueAsBit("isIndirectBranch");
+ isCompare = R->getValueAsBit("isCompare");
+ isMoveImm = R->getValueAsBit("isMoveImm");
+ isBarrier = R->getValueAsBit("isBarrier");
+ isCall = R->getValueAsBit("isCall");
+ canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
+ mayLoad = R->getValueAsBit("mayLoad");
+ mayStore = R->getValueAsBit("mayStore");
+ isPredicable = Operands.isPredicable || R->getValueAsBit("isPredicable");
+ isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
+ isCommutable = R->getValueAsBit("isCommutable");
+ isTerminator = R->getValueAsBit("isTerminator");
+ isReMaterializable = R->getValueAsBit("isReMaterializable");
+ hasDelaySlot = R->getValueAsBit("hasDelaySlot");
+ usesCustomInserter = R->getValueAsBit("usesCustomInserter");
+ hasCtrlDep = R->getValueAsBit("hasCtrlDep");
+ isNotDuplicable = R->getValueAsBit("isNotDuplicable");
+ hasSideEffects = R->getValueAsBit("hasSideEffects");
+ neverHasSideEffects = R->getValueAsBit("neverHasSideEffects");
+ isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove");
+ hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq");
+ hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq");
+ ImplicitDefs = R->getValueAsListOfDefs("Defs");
+ ImplicitUses = R->getValueAsListOfDefs("Uses");
+
+ if (neverHasSideEffects + hasSideEffects > 1)
+ throw R->getName() + ": multiple conflicting side-effect flags set!";
+
+ // Parse Constraints.
+ ParseConstraints(R->getValueAsString("Constraints"), Operands);
+
+ // Parse the DisableEncoding field.
+ Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding"));
+}
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
/// implicit def and it has a known VT, return the VT, otherwise return
@@ -293,14 +326,212 @@ CodeGenInstruction::ParseOperandName(const std::string &Op,
MVT::SimpleValueType CodeGenInstruction::
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
if (ImplicitDefs.empty()) return MVT::Other;
-
+
// Check to see if the first implicit def has a resolvable type.
Record *FirstImplicitDef = ImplicitDefs[0];
assert(FirstImplicitDef->isSubClassOf("Register"));
- const std::vector<MVT::SimpleValueType> &RegVTs =
+ const std::vector<MVT::SimpleValueType> &RegVTs =
TargetInfo.getRegisterVTs(FirstImplicitDef);
if (RegVTs.size() == 1)
return RegVTs[0];
return MVT::Other;
}
+
+/// FlattenAsmStringVariants - Flatten the specified AsmString to only
+/// include text from the specified variant, returning the new string.
+std::string CodeGenInstruction::
+FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
+ std::string Res = "";
+
+ for (;;) {
+ // Find the start of the next variant string.
+ size_t VariantsStart = 0;
+ for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)
+ if (Cur[VariantsStart] == '{' &&
+ (VariantsStart == 0 || (Cur[VariantsStart-1] != '$' &&
+ Cur[VariantsStart-1] != '\\')))
+ break;
+
+ // Add the prefix to the result.
+ Res += Cur.slice(0, VariantsStart);
+ if (VariantsStart == Cur.size())
+ break;
+
+ ++VariantsStart; // Skip the '{'.
+
+ // Scan to the end of the variants string.
+ size_t VariantsEnd = VariantsStart;
+ unsigned NestedBraces = 1;
+ for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {
+ if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') {
+ if (--NestedBraces == 0)
+ break;
+ } else if (Cur[VariantsEnd] == '{')
+ ++NestedBraces;
+ }
+
+ // Select the Nth variant (or empty).
+ StringRef Selection = Cur.slice(VariantsStart, VariantsEnd);
+ for (unsigned i = 0; i != Variant; ++i)
+ Selection = Selection.split('|').second;
+ Res += Selection.split('|').first;
+
+ assert(VariantsEnd != Cur.size() &&
+ "Unterminated variants in assembly string!");
+ Cur = Cur.substr(VariantsEnd + 1);
+ }
+
+ return Res;
+}
+
+
+//===----------------------------------------------------------------------===//
+/// CodeGenInstAlias Implementation
+//===----------------------------------------------------------------------===//
+
+/// tryAliasOpMatch - This is a helper function for the CodeGenInstAlias
+/// constructor. It checks if an argument in an InstAlias pattern matches
+/// the corresponding operand of the instruction. It returns true on a
+/// successful match, with ResOp set to the result operand to be used.
+bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
+ Record *InstOpRec, bool hasSubOps,
+ SMLoc Loc, CodeGenTarget &T,
+ ResultOperand &ResOp) {
+ Init *Arg = Result->getArg(AliasOpNo);
+ DefInit *ADI = dynamic_cast<DefInit*>(Arg);
+
+ if (ADI && ADI->getDef() == InstOpRec) {
+ // If the operand is a record, it must have a name, and the record type
+ // must match up with the instruction's argument type.
+ if (Result->getArgName(AliasOpNo).empty())
+ throw TGError(Loc, "result argument #" + utostr(AliasOpNo) +
+ " must have a name!");
+ ResOp = ResultOperand(Result->getArgName(AliasOpNo), ADI->getDef());
+ return true;
+ }
+
+ // Handle explicit registers.
+ if (ADI && ADI->getDef()->isSubClassOf("Register")) {
+ if (!InstOpRec->isSubClassOf("RegisterClass"))
+ return false;
+
+ if (!T.getRegisterClass(InstOpRec).containsRegister(ADI->getDef()))
+ throw TGError(Loc, "fixed register " +ADI->getDef()->getName()
+ + " is not a member of the " + InstOpRec->getName() +
+ " register class!");
+
+ if (!Result->getArgName(AliasOpNo).empty())
+ throw TGError(Loc, "result fixed register argument must "
+ "not have a name!");
+
+ ResOp = ResultOperand(ADI->getDef());
+ return true;
+ }
+
+ // Handle "zero_reg" for optional def operands.
+ if (ADI && ADI->getDef()->getName() == "zero_reg") {
+
+ // Check if this is an optional def.
+ if (!InstOpRec->isSubClassOf("OptionalDefOperand"))
+ throw TGError(Loc, "reg0 used for result that is not an "
+ "OptionalDefOperand!");
+
+ ResOp = ResultOperand(static_cast<Record*>(0));
+ return true;
+ }
+
+ if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
+ if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
+ return false;
+ // Integer arguments can't have names.
+ if (!Result->getArgName(AliasOpNo).empty())
+ throw TGError(Loc, "result argument #" + utostr(AliasOpNo) +
+ " must not have a name!");
+ ResOp = ResultOperand(II->getValue());
+ return true;
+ }
+
+ return false;
+}
+
+CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
+ AsmString = R->getValueAsString("AsmString");
+ Result = R->getValueAsDag("ResultInst");
+
+ // Verify that the root of the result is an instruction.
+ DefInit *DI = dynamic_cast<DefInit*>(Result->getOperator());
+ if (DI == 0 || !DI->getDef()->isSubClassOf("Instruction"))
+ throw TGError(R->getLoc(), "result of inst alias should be an instruction");
+
+ ResultInst = &T.getInstruction(DI->getDef());
+
+ // NameClass - If argument names are repeated, we need to verify they have
+ // the same class.
+ StringMap<Record*> NameClass;
+ for (unsigned i = 0, e = Result->getNumArgs(); i != e; ++i) {
+ DefInit *ADI = dynamic_cast<DefInit*>(Result->getArg(i));
+ if (!ADI || Result->getArgName(i).empty())
+ continue;
+ // Verify we don't have something like: (someinst GR16:$foo, GR32:$foo)
+ // $foo can exist multiple times in the result list, but it must have the
+ // same type.
+ Record *&Entry = NameClass[Result->getArgName(i)];
+ if (Entry && Entry != ADI->getDef())
+ throw TGError(R->getLoc(), "result value $" + Result->getArgName(i) +
+ " is both " + Entry->getName() + " and " +
+ ADI->getDef()->getName() + "!");
+ Entry = ADI->getDef();
+ }
+
+ // Decode and validate the arguments of the result.
+ unsigned AliasOpNo = 0;
+ for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
+
+ // Tied registers don't have an entry in the result dag.
+ if (ResultInst->Operands[i].getTiedRegister() != -1)
+ continue;
+
+ if (AliasOpNo >= Result->getNumArgs())
+ throw TGError(R->getLoc(), "not enough arguments for instruction!");
+
+ Record *InstOpRec = ResultInst->Operands[i].Rec;
+ unsigned NumSubOps = ResultInst->Operands[i].MINumOperands;
+ ResultOperand ResOp(static_cast<int64_t>(0));
+ if (tryAliasOpMatch(Result, AliasOpNo, InstOpRec, (NumSubOps > 1),
+ R->getLoc(), T, ResOp)) {
+ ResultOperands.push_back(ResOp);
+ ResultInstOperandIndex.push_back(std::make_pair(i, -1));
+ ++AliasOpNo;
+ continue;
+ }
+
+ // If the argument did not match the instruction operand, and the operand
+ // is composed of multiple suboperands, try matching the suboperands.
+ if (NumSubOps > 1) {
+ DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo;
+ for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
+ if (AliasOpNo >= Result->getNumArgs())
+ throw TGError(R->getLoc(), "not enough arguments for instruction!");
+ Record *SubRec = dynamic_cast<DefInit*>(MIOI->getArg(SubOp))->getDef();
+ if (tryAliasOpMatch(Result, AliasOpNo, SubRec, false,
+ R->getLoc(), T, ResOp)) {
+ ResultOperands.push_back(ResOp);
+ ResultInstOperandIndex.push_back(std::make_pair(i, SubOp));
+ ++AliasOpNo;
+ } else {
+ throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
+ " does not match instruction operand class " +
+ (SubOp == 0 ? InstOpRec->getName() :SubRec->getName()));
+ }
+ }
+ continue;
+ }
+ throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
+ " does not match instruction operand class " +
+ InstOpRec->getName());
+ }
+
+ if (AliasOpNo != Result->getNumArgs())
+ throw TGError(R->getLoc(), "too many operands for instruction!");
+}
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index b02d0d38f975..58913b9da26b 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -15,6 +15,8 @@
#define CODEGEN_INSTRUCTION_H
#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SourceMgr.h"
#include <string>
#include <vector>
#include <utility>
@@ -23,22 +25,16 @@ namespace llvm {
class Record;
class DagInit;
class CodeGenTarget;
-
- class CodeGenInstruction {
+ class StringRef;
+
+ class CGIOperandList {
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;
-
class ConstraintInfo {
enum { None, EarlyClobber, Tied } Kind;
unsigned OtherTiedOperand;
public:
ConstraintInfo() : Kind(None) {}
-
+
static ConstraintInfo getEarlyClobber() {
ConstraintInfo I;
I.Kind = EarlyClobber;
@@ -62,22 +58,26 @@ namespace llvm {
return OtherTiedOperand;
}
};
-
+
/// 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;
-
+
+ /// EncoderMethodName - The method used to get the machine operand value
+ /// for binary encoding. "getMachineOpValue" by default.
+ std::string EncoderMethodName;
+
/// 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
@@ -86,7 +86,7 @@ namespace llvm {
/// 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.
@@ -99,52 +99,61 @@ namespace llvm {
/// Constraint info for this operand. This operand can have pieces, so we
/// track constraint info for each.
std::vector<ConstraintInfo> 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) {}
+
+ OperandInfo(Record *R, const std::string &N, const std::string &PMN,
+ const std::string &EMN, unsigned MION, unsigned MINO,
+ DagInit *MIOI)
+ : Rec(R), Name(N), PrinterMethodName(PMN), EncoderMethodName(EMN),
+ MIOperandNo(MION), MINumOperands(MINO), MIOperandInfo(MIOI) {}
+
+
+ /// getTiedOperand - If this operand is tied to another one, return the
+ /// other operand number. Otherwise, return -1.
+ int getTiedRegister() const {
+ for (unsigned j = 0, e = Constraints.size(); j != e; ++j) {
+ const CGIOperandList::ConstraintInfo &CI = Constraints[j];
+ if (CI.isTied()) return CI.getTiedOperand();
+ }
+ return -1;
+ }
};
+
+ CGIOperandList(Record *D);
+
+ Record *TheDef; // The actual record containing this OperandList.
/// NumDefs - Number of def operands declared, this is the number of
/// elements in the instruction's (outs) list.
///
unsigned NumDefs;
-
+
/// OperandList - The list of declared operands, along with their declared
/// type (which is a record).
std::vector<OperandInfo> OperandList;
-
- /// ImplicitDefs/ImplicitUses - These are lists of registers that are
- /// implicitly defined and used by the instruction.
- std::vector<Record*> ImplicitDefs, ImplicitUses;
-
- // Various boolean values we track for the instruction.
- bool isReturn;
- bool isBranch;
- bool isIndirectBranch;
- bool isCompare;
- bool isBarrier;
- bool isCall;
- bool canFoldAsLoad;
- bool mayLoad, mayStore;
+
+ // Information gleaned from the operand list.
bool isPredicable;
- bool isConvertibleToThreeAddress;
- bool isCommutable;
- bool isTerminator;
- bool isReMaterializable;
- bool hasDelaySlot;
- bool usesCustomInserter;
- bool isVariadic;
- bool hasCtrlDep;
- bool isNotDuplicable;
bool hasOptionalDef;
- bool hasSideEffects;
- bool neverHasSideEffects;
- bool isAsCheapAsAMove;
- bool hasExtraSrcRegAllocReq;
- bool hasExtraDefRegAllocReq;
+ bool isVariadic;
+
+ // Provide transparent accessors to the operand list.
+ unsigned size() const { return OperandList.size(); }
+ const OperandInfo &operator[](unsigned i) const { return OperandList[i]; }
+ OperandInfo &operator[](unsigned i) { return OperandList[i]; }
+ OperandInfo &back() { return OperandList.back(); }
+ const OperandInfo &back() const { return OperandList.back(); }
+
+
+ /// 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(StringRef Name) const;
+ /// hasOperandNamed - Query whether the instruction has an operand of the
+ /// given name. If so, return true and set OpIdx to the index of the
+ /// operand. Otherwise, return false.
+ bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;
+
/// 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
@@ -178,20 +187,130 @@ namespace llvm {
return OperandList[Op.first].DoNotEncode[Op.second];
return false;
}
+
+ void ProcessDisableEncoding(std::string Value);
+ };
+
- CodeGenInstruction(Record *R, const std::string &AsmStr);
+ 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;
+
+ /// Operands - This is information about the (ins) and (outs) list specified
+ /// to the instruction.
+ CGIOperandList Operands;
+
+ /// ImplicitDefs/ImplicitUses - These are lists of registers that are
+ /// implicitly defined and used by the instruction.
+ std::vector<Record*> ImplicitDefs, ImplicitUses;
+
+ // Various boolean values we track for the instruction.
+ bool isReturn;
+ bool isBranch;
+ bool isIndirectBranch;
+ bool isCompare;
+ bool isMoveImm;
+ bool isBarrier;
+ bool isCall;
+ bool canFoldAsLoad;
+ bool mayLoad, mayStore;
+ bool isPredicable;
+ bool isConvertibleToThreeAddress;
+ bool isCommutable;
+ bool isTerminator;
+ bool isReMaterializable;
+ bool hasDelaySlot;
+ bool usesCustomInserter;
+ bool hasCtrlDep;
+ bool isNotDuplicable;
+ bool hasSideEffects;
+ bool neverHasSideEffects;
+ bool isAsCheapAsAMove;
+ bool hasExtraSrcRegAllocReq;
+ bool hasExtraDefRegAllocReq;
+
+
+ CodeGenInstruction(Record *R);
- /// 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;
-
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
/// implicit def and it has a known VT, return the VT, otherwise return
/// MVT::Other.
- MVT::SimpleValueType
+ MVT::SimpleValueType
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const;
+
+
+ /// FlattenAsmStringVariants - Flatten the specified AsmString to only
+ /// include text from the specified variant, returning the new string.
+ static std::string FlattenAsmStringVariants(StringRef AsmString,
+ unsigned Variant);
};
+
+
+ /// CodeGenInstAlias - This represents an InstAlias definition.
+ class CodeGenInstAlias {
+ public:
+ Record *TheDef; // The actual record defining this InstAlias.
+
+ /// AsmString - The format string used to emit a .s file for the
+ /// instruction.
+ std::string AsmString;
+
+ /// Result - The result instruction.
+ DagInit *Result;
+
+ /// ResultInst - The instruction generated by the alias (decoded from
+ /// Result).
+ CodeGenInstruction *ResultInst;
+
+
+ struct ResultOperand {
+ private:
+ StringRef Name;
+ Record *R;
+
+ int64_t Imm;
+ public:
+ enum {
+ K_Record,
+ K_Imm,
+ K_Reg
+ } Kind;
+
+ ResultOperand(StringRef N, Record *r) : Name(N), R(r), Kind(K_Record) {}
+ ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
+ ResultOperand(Record *r) : R(r), Kind(K_Reg) {}
+
+ bool isRecord() const { return Kind == K_Record; }
+ bool isImm() const { return Kind == K_Imm; }
+ bool isReg() const { return Kind == K_Reg; }
+
+ StringRef getName() const { assert(isRecord()); return Name; }
+ Record *getRecord() const { assert(isRecord()); return R; }
+ int64_t getImm() const { assert(isImm()); return Imm; }
+ Record *getRegister() const { assert(isReg()); return R; }
+ };
+
+ /// ResultOperands - The decoded operands for the result instruction.
+ std::vector<ResultOperand> ResultOperands;
+
+ /// ResultInstOperandIndex - For each operand, this vector holds a pair of
+ /// indices to identify the corresponding operand in the result
+ /// instruction. The first index specifies the operand and the second
+ /// index specifies the suboperand. If there are no suboperands or if all
+ /// of them are matched by the operand, the second value should be -1.
+ std::vector<std::pair<unsigned, int> > ResultInstOperandIndex;
+
+ CodeGenInstAlias(Record *R, CodeGenTarget &T);
+
+ bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
+ Record *InstOpRec, bool hasSubOps, SMLoc Loc,
+ CodeGenTarget &T, ResultOperand &ResOp);
+ };
}
#endif
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index ccd3d222bbad..bbd0cefa5804 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -57,6 +57,12 @@ namespace llvm {
abort();
}
+ bool containsRegister(Record *R) const {
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i)
+ if (Elements[i] == R) return true;
+ return false;
+ }
+
// Returns true if RC is a strict subclass.
// RC is a sub-class of this class if it is a valid replacement for any
// instruction operand where a register of this classis required. It must
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index cbfe2addbf2b..d0f7d8b44079 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -48,46 +48,47 @@ std::string llvm::getName(MVT::SimpleValueType T) {
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::vAny: return "MVT::vAny";
- 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::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::vAny: return "MVT::vAny";
+ 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::v8i8: return "MVT::v8i8";
- case MVT::v16i8: return "MVT::v16i8";
- case MVT::v32i8: return "MVT::v32i8";
- case MVT::v2i16: return "MVT::v2i16";
- case MVT::v4i16: return "MVT::v4i16";
- case MVT::v8i16: return "MVT::v8i16";
- case MVT::v16i16: return "MVT::v16i16";
- case MVT::v2i32: return "MVT::v2i32";
- case MVT::v4i32: return "MVT::v4i32";
- case MVT::v8i32: return "MVT::v8i32";
- case MVT::v1i64: return "MVT::v1i64";
- case MVT::v2i64: return "MVT::v2i64";
- case MVT::v4i64: return "MVT::v4i64";
- case MVT::v8i64: return "MVT::v8i64";
- case MVT::v2f32: return "MVT::v2f32";
- case MVT::v4f32: return "MVT::v4f32";
- case MVT::v8f32: return "MVT::v8f32";
- case MVT::v2f64: return "MVT::v2f64";
- case MVT::v4f64: return "MVT::v4f64";
+ case MVT::x86mmx: return "MVT::x86mmx";
+ case MVT::Glue: return "MVT::Glue";
+ case MVT::isVoid: return "MVT::isVoid";
+ case MVT::v2i8: return "MVT::v2i8";
+ case MVT::v4i8: return "MVT::v4i8";
+ case MVT::v8i8: return "MVT::v8i8";
+ case MVT::v16i8: return "MVT::v16i8";
+ case MVT::v32i8: return "MVT::v32i8";
+ case MVT::v2i16: return "MVT::v2i16";
+ case MVT::v4i16: return "MVT::v4i16";
+ case MVT::v8i16: return "MVT::v8i16";
+ case MVT::v16i16: return "MVT::v16i16";
+ case MVT::v2i32: return "MVT::v2i32";
+ case MVT::v4i32: return "MVT::v4i32";
+ case MVT::v8i32: return "MVT::v8i32";
+ case MVT::v1i64: return "MVT::v1i64";
+ case MVT::v2i64: return "MVT::v2i64";
+ case MVT::v4i64: return "MVT::v4i64";
+ case MVT::v8i64: return "MVT::v8i64";
+ case MVT::v2f32: return "MVT::v2f32";
+ case MVT::v4f32: return "MVT::v4f32";
+ case MVT::v8f32: return "MVT::v8f32";
+ case MVT::v2f64: return "MVT::v2f64";
+ case MVT::v4f64: return "MVT::v4f64";
case MVT::Metadata: return "MVT::Metadata";
- case MVT::iPTR: return "MVT::iPTR";
+ case MVT::iPTR: return "MVT::iPTR";
case MVT::iPTRAny: return "MVT::iPTRAny";
default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
}
@@ -107,7 +108,7 @@ std::string llvm::getQualifiedName(const Record *R) {
/// getTarget - Return the current instance of the Target class.
///
-CodeGenTarget::CodeGenTarget() {
+CodeGenTarget::CodeGenTarget(RecordKeeper &records) : Records(records) {
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
if (Targets.size() == 0)
throw std::string("ERROR: No 'Target' subclasses defined!");
@@ -189,6 +190,19 @@ void CodeGenTarget::ReadRegisterClasses() const {
RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
}
+/// getRegisterByName - If there is a register with the specific AsmName,
+/// return it.
+const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {
+ const std::vector<CodeGenRegister> &Regs = getRegisters();
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ const CodeGenRegister &Reg = Regs[i];
+ if (Reg.TheDef->getValueAsString("AsmName") == Name)
+ return &Reg;
+ }
+
+ return 0;
+}
+
std::vector<MVT::SimpleValueType> CodeGenTarget::
getRegisterVTs(Record *R) const {
std::vector<MVT::SimpleValueType> Result;
@@ -294,18 +308,14 @@ void CodeGenTarget::ReadInstructions() const {
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[Insts[i]] = new CodeGenInstruction(Insts[i], AsmStr);
- }
+ for (unsigned i = 0, e = Insts.size(); i != e; ++i)
+ Instructions[Insts[i]] = new CodeGenInstruction(Insts[i]);
}
static const CodeGenInstruction *
GetInstByName(const char *Name,
- const DenseMap<const Record*, CodeGenInstruction*> &Insts) {
+ const DenseMap<const Record*, CodeGenInstruction*> &Insts,
+ RecordKeeper &Records) {
const Record *Rec = Records.getDef(Name);
DenseMap<const Record*, CodeGenInstruction*>::const_iterator
@@ -349,7 +359,7 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
};
const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();
for (const char *const *p = FixedInstrs; *p; ++p) {
- const CodeGenInstruction *Instr = GetInstByName(*p, Insts);
+ const CodeGenInstruction *Instr = GetInstByName(*p, Insts, Records);
assert(Instr && "Missing target independent instruction");
assert(Instr->Namespace == "TargetOpcode" && "Bad namespace");
InstrsByEnum.push_back(Instr);
@@ -394,8 +404,8 @@ ComplexPattern::ComplexPattern(Record *R) {
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() == "SDNPOptInGlue") {
+ Properties |= 1 << SDNPOptInGlue;
} else if (PropList[i]->getName() == "SDNPMayStore") {
Properties |= 1 << SDNPMayStore;
} else if (PropList[i]->getName() == "SDNPMayLoad") {
@@ -406,6 +416,10 @@ ComplexPattern::ComplexPattern(Record *R) {
Properties |= 1 << SDNPMemOperand;
} else if (PropList[i]->getName() == "SDNPVariadic") {
Properties |= 1 << SDNPVariadic;
+ } else if (PropList[i]->getName() == "SDNPWantRoot") {
+ Properties |= 1 << SDNPWantRoot;
+ } else if (PropList[i]->getName() == "SDNPWantParent") {
+ Properties |= 1 << SDNPWantParent;
} else {
errs() << "Unsupported SD Node property '" << PropList[i]->getName()
<< "' on ComplexPattern '" << R->getName() << "'!\n";
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index 6b06b66c29bc..f1058eb63181 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -35,14 +35,16 @@ enum SDNP {
SDNPCommutative,
SDNPAssociative,
SDNPHasChain,
- SDNPOutFlag,
- SDNPInFlag,
- SDNPOptInFlag,
+ SDNPOutGlue,
+ SDNPInGlue,
+ SDNPOptInGlue,
SDNPMayLoad,
SDNPMayStore,
SDNPSideEffect,
SDNPMemOperand,
- SDNPVariadic
+ SDNPVariadic,
+ SDNPWantRoot,
+ SDNPWantParent
};
/// getValueType - Return the MVT::SimpleValueType that the specified TableGen
@@ -59,6 +61,7 @@ std::string getQualifiedName(const Record *R);
/// CodeGenTarget - This class corresponds to the Target class in the .td files.
///
class CodeGenTarget {
+ RecordKeeper &Records;
Record *TargetRec;
mutable DenseMap<const Record*, CodeGenInstruction*> Instructions;
@@ -74,7 +77,7 @@ class CodeGenTarget {
mutable std::vector<const CodeGenInstruction*> InstrsByEnum;
public:
- CodeGenTarget();
+ CodeGenTarget(RecordKeeper &Records);
Record *getTargetRecord() const { return TargetRec; }
const std::string &getName() const;
@@ -99,6 +102,10 @@ public:
if (Registers.empty()) ReadRegisters();
return Registers;
}
+
+ /// getRegisterByName - If there is a register with the specific AsmName,
+ /// return it.
+ const CodeGenRegister *getRegisterByName(StringRef Name) const;
const std::vector<Record*> &getSubRegIndices() const {
if (SubRegIndices.empty()) ReadSubRegIndices();
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index 9f12a686e4cf..2afa2b907bc4 100644
--- a/utils/TableGen/DAGISelMatcher.cpp
+++ b/utils/TableGen/DAGISelMatcher.cpp
@@ -35,7 +35,7 @@ void Matcher::printOne(raw_ostream &OS) const {
Matcher *Matcher::unlinkNode(Matcher *Other) {
if (this == Other)
return takeNext();
-
+
// Scan until we find the predecessor of Other.
Matcher *Cur = this;
for (; Cur && Cur->getNext() != Other; Cur = Cur->getNext())
@@ -67,11 +67,11 @@ bool Matcher::canMoveBeforeNode(const Matcher *Other) const {
// We can move simple predicates before record nodes.
if (isSimplePredicateNode())
return Other->isSimplePredicateOrRecordNode();
-
+
// We can move record nodes across simple predicates.
if (isSimplePredicateOrRecordNode())
return isSimplePredicateNode();
-
+
// We can't move record nodes across each other etc.
return false;
}
@@ -107,8 +107,8 @@ void RecordMemRefMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent) << "RecordMemRef\n";
}
-void CaptureFlagInputMatcher::printImpl(raw_ostream &OS, unsigned indent) const{
- OS.indent(indent) << "CaptureFlagInput\n";
+void CaptureGlueInputMatcher::printImpl(raw_ostream &OS, unsigned indent) const{
+ OS.indent(indent) << "CaptureGlueInput\n";
}
void MoveChildMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
@@ -246,8 +246,8 @@ void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const {
OS << ")\n";
}
-void MarkFlagResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
- OS.indent(indent) << "MarkFlagResults <todo: args>\n";
+void MarkGlueResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
+ OS.indent(indent) << "MarkGlueResults <todo: args>\n";
}
void CompleteMatchMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
@@ -296,7 +296,7 @@ unsigned EmitMergeInputChainsMatcher::getHashImpl() const {
bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const {
// Note: pointer equality isn't enough here, we have to check the enum names
- // to ensure that the nodes are for the same opcode.
+ // to ensure that the nodes are for the same opcode.
return cast<CheckOpcodeMatcher>(M)->Opcode.getEnumName() ==
Opcode.getEnumName();
}
@@ -306,7 +306,7 @@ bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const {
const EmitNodeMatcherCommon *M = cast<EmitNodeMatcherCommon>(m);
return M->OpcodeName == OpcodeName && M->VTs == VTs &&
M->Operands == Operands && M->HasChain == HasChain &&
- M->HasInFlag == HasInFlag && M->HasOutFlag == HasOutFlag &&
+ M->HasInGlue == HasInGlue && M->HasOutGlue == HasOutGlue &&
M->HasMemRefs == HasMemRefs &&
M->NumFixedArityOperands == NumFixedArityOperands;
}
@@ -316,12 +316,12 @@ unsigned EmitNodeMatcherCommon::getHashImpl() const {
}
-unsigned MarkFlagResultsMatcher::getHashImpl() const {
- return HashUnsigneds(FlagResultNodes.begin(), FlagResultNodes.end());
+unsigned MarkGlueResultsMatcher::getHashImpl() const {
+ return HashUnsigneds(GlueResultNodes.begin(), GlueResultNodes.end());
}
unsigned CompleteMatchMatcher::getHashImpl() const {
- return HashUnsigneds(Results.begin(), Results.end()) ^
+ return HashUnsigneds(Results.begin(), Results.end()) ^
((unsigned)(intptr_t)&Pattern << 8);
}
@@ -332,15 +332,15 @@ static bool TypesAreContradictory(MVT::SimpleValueType T1,
// If the two types are the same, then they are the same, so they don't
// contradict.
if (T1 == T2) return false;
-
+
// If either type is about iPtr, then they don't conflict unless the other
// one is not a scalar integer type.
if (T1 == MVT::iPTR)
return !MVT(T2).isInteger() || MVT(T2).isVector();
-
+
if (T2 == MVT::iPTR)
return !MVT(T1).isInteger() || MVT(T1).isVector();
-
+
// Otherwise, they are two different non-iPTR types, they conflict.
return true;
}
@@ -349,10 +349,10 @@ bool CheckOpcodeMatcher::isContradictoryImpl(const Matcher *M) const {
if (const CheckOpcodeMatcher *COM = dyn_cast<CheckOpcodeMatcher>(M)) {
// One node can't have two different opcodes!
// Note: pointer equality isn't enough here, we have to check the enum names
- // to ensure that the nodes are for the same opcode.
+ // to ensure that the nodes are for the same opcode.
return COM->getOpcode().getEnumName() != getOpcode().getEnumName();
}
-
+
// If the node has a known type, and if the type we're checking for is
// different, then we know they contradict. For example, a check for
// ISD::STORE will never be true at the same time a check for Type i32 is.
@@ -360,12 +360,12 @@ bool CheckOpcodeMatcher::isContradictoryImpl(const Matcher *M) const {
// If checking for a result the opcode doesn't have, it can't match.
if (CT->getResNo() >= getOpcode().getNumResults())
return true;
-
+
MVT::SimpleValueType NodeType = getOpcode().getKnownType(CT->getResNo());
if (NodeType != MVT::Other)
return TypesAreContradictory(NodeType, CT->getType());
}
-
+
return false;
}
@@ -381,12 +381,12 @@ bool CheckChildTypeMatcher::isContradictoryImpl(const Matcher *M) const {
// conflict!
if (CC->getChildNo() != getChildNo())
return false;
-
+
return TypesAreContradictory(getType(), CC->getType());
}
return false;
}
-
+
bool CheckIntegerMatcher::isContradictoryImpl(const Matcher *M) const {
if (const CheckIntegerMatcher *CIM = dyn_cast<CheckIntegerMatcher>(M))
return CIM->getValue() != getValue();
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index d9b25d556430..8e6e44647ea1 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -31,7 +31,7 @@ Matcher *OptimizeMatcher(Matcher *Matcher, const CodeGenDAGPatterns &CGP);
void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP,
raw_ostream &OS);
-
+
/// Matcher - Base class for all the the DAG ISel Matcher representation
/// nodes.
class Matcher {
@@ -45,10 +45,10 @@ public:
RecordNode, // Record the current node.
RecordChild, // Record a child of the current node.
RecordMemRef, // Record the memref in the current node.
- CaptureFlagInput, // If the current node has an input flag, save it.
+ CaptureGlueInput, // If the current node has an input glue, save it.
MoveChild, // Move current node to specified child.
MoveParent, // Move current node to parent.
-
+
// Predicate checking.
CheckSame, // Fail if not same as prev match.
CheckPatternPredicate,
@@ -65,7 +65,7 @@ public:
CheckAndImm,
CheckOrImm,
CheckFoldableChainNode,
-
+
// Node creation/emisssion.
EmitInteger, // Create a TargetConstant
EmitStringInteger, // Create a TargetConstant from a string.
@@ -75,7 +75,7 @@ public:
EmitCopyToReg, // Emit a copytoreg into a physreg.
EmitNode, // Create a DAG node
EmitNodeXForm, // Run a SDNodeXForm
- MarkFlagResults, // Indicate which interior nodes have flag results.
+ MarkGlueResults, // Indicate which interior nodes have glue results.
CompleteMatch, // Finish a match and update the results.
MorphNodeTo // Build a node, finish a match and update results.
};
@@ -85,7 +85,7 @@ protected:
Matcher(KindTy K) : Kind(K) {}
public:
virtual ~Matcher() {}
-
+
KindTy getKind() const { return Kind; }
Matcher *getNext() { return Next.get(); }
@@ -94,25 +94,25 @@ public:
Matcher *takeNext() { return Next.take(); }
OwningPtr<Matcher> &getNextPtr() { return Next; }
-
+
static inline bool classof(const Matcher *) { return true; }
-
+
bool isEqual(const Matcher *M) const {
if (getKind() != M->getKind()) return false;
return isEqualImpl(M);
}
-
+
unsigned getHash() const {
// Clear the high bit so we don't conflict with tombstones etc.
return ((getHashImpl() << 4) ^ getKind()) & (~0U>>1);
}
-
+
/// isSafeToReorderWithPatternPredicate - Return true if it is safe to sink a
/// PatternPredicate node past this one.
virtual bool isSafeToReorderWithPatternPredicate() const {
return false;
}
-
+
/// isSimplePredicateNode - Return true if this is a simple predicate that
/// operates on the node or its children without potential side effects or a
/// change of the current node.
@@ -134,28 +134,28 @@ public:
return true;
}
}
-
+
/// isSimplePredicateOrRecordNode - Return true if this is a record node or
/// a simple predicate.
bool isSimplePredicateOrRecordNode() const {
return isSimplePredicateNode() ||
getKind() == RecordNode || getKind() == RecordChild;
}
-
+
/// unlinkNode - Unlink the specified node from this chain. If Other == this,
/// we unlink the next pointer and return it. Otherwise we unlink Other from
/// the list and return this.
Matcher *unlinkNode(Matcher *Other);
-
+
/// canMoveBefore - Return true if this matcher is the same as Other, or if
/// we can move this matcher past all of the nodes in-between Other and this
/// node. Other must be equal to or before this.
bool canMoveBefore(const Matcher *Other) const;
-
+
/// canMoveBefore - Return true if it is safe to move the current matcher
/// across the specified one.
bool canMoveBeforeNode(const Matcher *Other) const;
-
+
/// isContradictory - Return true of these two matchers could never match on
/// the same node.
bool isContradictory(const Matcher *Other) const {
@@ -167,7 +167,7 @@ public:
return isContradictoryImpl(Other);
return Other->isContradictoryImpl(this);
}
-
+
void print(raw_ostream &OS, unsigned indent = 0) const;
void printOne(raw_ostream &OS) const;
void dump() const;
@@ -177,7 +177,7 @@ protected:
virtual unsigned getHashImpl() const = 0;
virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
};
-
+
/// ScopeMatcher - This attempts to match each of its children to find the first
/// one that successfully matches. If one child fails, it tries the next child.
/// If none of the children match then this check fails. It never has a 'next'.
@@ -188,12 +188,12 @@ public:
: Matcher(Scope), Children(children, children+numchildren) {
}
virtual ~ScopeMatcher();
-
+
unsigned getNumChildren() const { return Children.size(); }
-
+
Matcher *getChild(unsigned i) { return Children[i]; }
const Matcher *getChild(unsigned i) const { return Children[i]; }
-
+
void resetChild(unsigned i, Matcher *N) {
delete Children[i];
Children[i] = N;
@@ -204,7 +204,7 @@ public:
Children[i] = 0;
return Res;
}
-
+
void setNumChildren(unsigned NC) {
if (NC < Children.size()) {
// delete any children we're about to lose pointers to.
@@ -217,7 +217,7 @@ public:
static inline bool classof(const Matcher *N) {
return N->getKind() == Scope;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const { return false; }
@@ -229,38 +229,38 @@ class RecordMatcher : public Matcher {
/// WhatFor - This is a string indicating why we're recording this. This
/// should only be used for comment generation not anything semantic.
std::string WhatFor;
-
+
/// ResultNo - The slot number in the RecordedNodes vector that this will be,
/// just printed as a comment.
unsigned ResultNo;
public:
RecordMatcher(const std::string &whatfor, unsigned resultNo)
: Matcher(RecordNode), WhatFor(whatfor), ResultNo(resultNo) {}
-
+
const std::string &getWhatFor() const { return WhatFor; }
unsigned getResultNo() const { return ResultNo; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == RecordNode;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const { return true; }
virtual unsigned getHashImpl() const { return 0; }
};
-
+
/// RecordChildMatcher - Save a numbered child of the current node, or fail
/// the match if it doesn't exist. This is logically equivalent to:
/// MoveChild N + RecordNode + MoveParent.
class RecordChildMatcher : public Matcher {
unsigned ChildNo;
-
+
/// WhatFor - This is a string indicating why we're recording this. This
/// should only be used for comment generation not anything semantic.
std::string WhatFor;
-
+
/// ResultNo - The slot number in the RecordedNodes vector that this will be,
/// just printed as a comment.
unsigned ResultNo;
@@ -269,7 +269,7 @@ public:
unsigned resultNo)
: Matcher(RecordChild), ChildNo(childno), WhatFor(whatfor),
ResultNo(resultNo) {}
-
+
unsigned getChildNo() const { return ChildNo; }
const std::string &getWhatFor() const { return WhatFor; }
unsigned getResultNo() const { return ResultNo; }
@@ -277,7 +277,7 @@ public:
static inline bool classof(const Matcher *N) {
return N->getKind() == RecordChild;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -287,16 +287,16 @@ private:
}
virtual unsigned getHashImpl() const { return getChildNo(); }
};
-
+
/// RecordMemRefMatcher - Save the current node's memref.
class RecordMemRefMatcher : public Matcher {
public:
RecordMemRefMatcher() : Matcher(RecordMemRef) {}
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == RecordMemRef;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -305,17 +305,17 @@ private:
virtual unsigned getHashImpl() const { return 0; }
};
-
-/// CaptureFlagInputMatcher - If the current record has a flag input, record
+
+/// CaptureGlueInputMatcher - If the current record has a glue input, record
/// it so that it is used as an input to the generated code.
-class CaptureFlagInputMatcher : public Matcher {
+class CaptureGlueInputMatcher : public Matcher {
public:
- CaptureFlagInputMatcher() : Matcher(CaptureFlagInput) {}
-
+ CaptureGlueInputMatcher() : Matcher(CaptureGlueInput) {}
+
static inline bool classof(const Matcher *N) {
- return N->getKind() == CaptureFlagInput;
+ return N->getKind() == CaptureGlueInput;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -323,20 +323,20 @@ private:
virtual bool isEqualImpl(const Matcher *M) const { return true; }
virtual unsigned getHashImpl() const { return 0; }
};
-
+
/// MoveChildMatcher - This tells the interpreter to move into the
/// specified child node.
class MoveChildMatcher : public Matcher {
unsigned ChildNo;
public:
MoveChildMatcher(unsigned childNo) : Matcher(MoveChild), ChildNo(childNo) {}
-
+
unsigned getChildNo() const { return ChildNo; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == MoveChild;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -346,17 +346,17 @@ private:
}
virtual unsigned getHashImpl() const { return getChildNo(); }
};
-
+
/// MoveParentMatcher - This tells the interpreter to move to the parent
/// of the current node.
class MoveParentMatcher : public Matcher {
public:
MoveParentMatcher() : Matcher(MoveParent) {}
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == MoveParent;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -373,13 +373,13 @@ class CheckSameMatcher : public Matcher {
public:
CheckSameMatcher(unsigned matchnumber)
: Matcher(CheckSame), MatchNumber(matchnumber) {}
-
+
unsigned getMatchNumber() const { return MatchNumber; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckSame;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -389,7 +389,7 @@ private:
}
virtual unsigned getHashImpl() const { return getMatchNumber(); }
};
-
+
/// CheckPatternPredicateMatcher - This checks the target-specific predicate
/// to see if the entire pattern is capable of matching. This predicate does
/// not take a node as input. This is used for subtarget feature checks etc.
@@ -398,13 +398,13 @@ class CheckPatternPredicateMatcher : public Matcher {
public:
CheckPatternPredicateMatcher(StringRef predicate)
: Matcher(CheckPatternPredicate), Predicate(predicate) {}
-
+
StringRef getPredicate() const { return Predicate; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckPatternPredicate;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -414,7 +414,7 @@ private:
}
virtual unsigned getHashImpl() const;
};
-
+
/// CheckPredicateMatcher - This checks the target-specific predicate to
/// see if the node is acceptable.
class CheckPredicateMatcher : public Matcher {
@@ -422,13 +422,13 @@ class CheckPredicateMatcher : public Matcher {
public:
CheckPredicateMatcher(StringRef predname)
: Matcher(CheckPredicate), PredName(predname) {}
-
+
StringRef getPredicateName() const { return PredName; }
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckPredicate;
}
-
+
// TODO: Ok?
//virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
@@ -439,8 +439,8 @@ private:
}
virtual unsigned getHashImpl() const;
};
-
-
+
+
/// CheckOpcodeMatcher - This checks to see if the current node has the
/// specified opcode, if not it fails to match.
class CheckOpcodeMatcher : public Matcher {
@@ -448,13 +448,13 @@ class CheckOpcodeMatcher : public Matcher {
public:
CheckOpcodeMatcher(const SDNodeInfo &opcode)
: Matcher(CheckOpcode), Opcode(opcode) {}
-
+
const SDNodeInfo &getOpcode() const { return Opcode; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckOpcode;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -478,19 +478,19 @@ public:
static inline bool classof(const Matcher *N) {
return N->getKind() == SwitchOpcode;
}
-
+
unsigned getNumCases() const { return Cases.size(); }
-
+
const SDNodeInfo &getCaseOpcode(unsigned i) const { return *Cases[i].first; }
Matcher *getCaseMatcher(unsigned i) { return Cases[i].second; }
const Matcher *getCaseMatcher(unsigned i) const { return Cases[i].second; }
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const { return false; }
virtual unsigned getHashImpl() const { return 4123; }
};
-
+
/// CheckTypeMatcher - This checks to see if the current node has the
/// specified type at the specified result, if not it fails to match.
class CheckTypeMatcher : public Matcher {
@@ -499,14 +499,14 @@ class CheckTypeMatcher : public Matcher {
public:
CheckTypeMatcher(MVT::SimpleValueType type, unsigned resno)
: Matcher(CheckType), Type(type), ResNo(resno) {}
-
+
MVT::SimpleValueType getType() const { return Type; }
unsigned getResNo() const { return ResNo; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckType;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -517,7 +517,7 @@ private:
virtual unsigned getHashImpl() const { return Type; }
virtual bool isContradictoryImpl(const Matcher *M) const;
};
-
+
/// SwitchTypeMatcher - Switch based on the current node's type, dispatching
/// to one matcher per case. If the type doesn't match any of the cases,
/// then the match fails. This is semantically equivalent to a Scope node where
@@ -528,24 +528,24 @@ public:
SwitchTypeMatcher(const std::pair<MVT::SimpleValueType, Matcher*> *cases,
unsigned numcases)
: Matcher(SwitchType), Cases(cases, cases+numcases) {}
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == SwitchType;
}
-
+
unsigned getNumCases() const { return Cases.size(); }
-
+
MVT::SimpleValueType getCaseType(unsigned i) const { return Cases[i].first; }
Matcher *getCaseMatcher(unsigned i) { return Cases[i].second; }
const Matcher *getCaseMatcher(unsigned i) const { return Cases[i].second; }
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const { return false; }
virtual unsigned getHashImpl() const { return 4123; }
};
-
-
+
+
/// CheckChildTypeMatcher - This checks to see if a child node has the
/// specified type, if not it fails to match.
class CheckChildTypeMatcher : public Matcher {
@@ -554,14 +554,14 @@ class CheckChildTypeMatcher : public Matcher {
public:
CheckChildTypeMatcher(unsigned childno, MVT::SimpleValueType type)
: Matcher(CheckChildType), ChildNo(childno), Type(type) {}
-
+
unsigned getChildNo() const { return ChildNo; }
MVT::SimpleValueType getType() const { return Type; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckChildType;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -573,7 +573,7 @@ private:
virtual unsigned getHashImpl() const { return (Type << 3) | ChildNo; }
virtual bool isContradictoryImpl(const Matcher *M) const;
};
-
+
/// CheckIntegerMatcher - This checks to see if the current node is a
/// ConstantSDNode with the specified integer value, if not it fails to match.
@@ -582,13 +582,13 @@ class CheckIntegerMatcher : public Matcher {
public:
CheckIntegerMatcher(int64_t value)
: Matcher(CheckInteger), Value(value) {}
-
+
int64_t getValue() const { return Value; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckInteger;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -599,7 +599,7 @@ private:
virtual unsigned getHashImpl() const { return Value; }
virtual bool isContradictoryImpl(const Matcher *M) const;
};
-
+
/// CheckCondCodeMatcher - This checks to see if the current node is a
/// CondCodeSDNode with the specified condition, if not it fails to match.
class CheckCondCodeMatcher : public Matcher {
@@ -607,13 +607,13 @@ class CheckCondCodeMatcher : public Matcher {
public:
CheckCondCodeMatcher(StringRef condcodename)
: Matcher(CheckCondCode), CondCodeName(condcodename) {}
-
+
StringRef getCondCodeName() const { return CondCodeName; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckCondCode;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -623,7 +623,7 @@ private:
}
virtual unsigned getHashImpl() const;
};
-
+
/// CheckValueTypeMatcher - This checks to see if the current node is a
/// VTSDNode with the specified type, if not it fails to match.
class CheckValueTypeMatcher : public Matcher {
@@ -631,13 +631,13 @@ class CheckValueTypeMatcher : public Matcher {
public:
CheckValueTypeMatcher(StringRef type_name)
: Matcher(CheckValueType), TypeName(type_name) {}
-
+
StringRef getTypeName() const { return TypeName; }
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckValueType;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -648,21 +648,21 @@ private:
virtual unsigned getHashImpl() const;
bool isContradictoryImpl(const Matcher *M) const;
};
-
-
-
+
+
+
/// CheckComplexPatMatcher - This node runs the specified ComplexPattern on
/// the current node.
class CheckComplexPatMatcher : public Matcher {
const ComplexPattern &Pattern;
-
- /// MatchNumber - This is the recorded nodes slot that contains the node we want to
- /// match against.
+
+ /// MatchNumber - This is the recorded nodes slot that contains the node we
+ /// want to match against.
unsigned MatchNumber;
-
+
/// Name - The name of the node we're matching, for comment emission.
std::string Name;
-
+
/// FirstResult - This is the first slot in the RecordedNodes list that the
/// result of the match populates.
unsigned FirstResult;
@@ -671,17 +671,17 @@ public:
const std::string &name, unsigned firstresult)
: Matcher(CheckComplexPat), Pattern(pattern), MatchNumber(matchnumber),
Name(name), FirstResult(firstresult) {}
-
+
const ComplexPattern &getPattern() const { return Pattern; }
unsigned getMatchNumber() const { return MatchNumber; }
-
+
const std::string getName() const { return Name; }
unsigned getFirstResult() const { return FirstResult; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckComplexPat;
}
-
+
// Not safe to move a pattern predicate past a complex pattern.
virtual bool isSafeToReorderWithPatternPredicate() const { return false; }
@@ -695,7 +695,7 @@ private:
return (unsigned)(intptr_t)&Pattern ^ MatchNumber;
}
};
-
+
/// CheckAndImmMatcher - This checks to see if the current node is an 'and'
/// with something equivalent to the specified immediate.
class CheckAndImmMatcher : public Matcher {
@@ -703,13 +703,13 @@ class CheckAndImmMatcher : public Matcher {
public:
CheckAndImmMatcher(int64_t value)
: Matcher(CheckAndImm), Value(value) {}
-
+
int64_t getValue() const { return Value; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckAndImm;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -727,13 +727,13 @@ class CheckOrImmMatcher : public Matcher {
public:
CheckOrImmMatcher(int64_t value)
: Matcher(CheckOrImm), Value(value) {}
-
+
int64_t getValue() const { return Value; }
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckOrImm;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -750,11 +750,11 @@ class CheckFoldableChainNodeMatcher : public Matcher {
public:
CheckFoldableChainNodeMatcher()
: Matcher(CheckFoldableChainNode) {}
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckFoldableChainNode;
}
-
+
virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
private:
@@ -770,14 +770,14 @@ class EmitIntegerMatcher : public Matcher {
public:
EmitIntegerMatcher(int64_t val, MVT::SimpleValueType vt)
: Matcher(EmitInteger), Val(val), VT(vt) {}
-
+
int64_t getValue() const { return Val; }
MVT::SimpleValueType getVT() const { return VT; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitInteger;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
@@ -795,14 +795,14 @@ class EmitStringIntegerMatcher : public Matcher {
public:
EmitStringIntegerMatcher(const std::string &val, MVT::SimpleValueType vt)
: Matcher(EmitStringInteger), Val(val), VT(vt) {}
-
+
const std::string &getValue() const { return Val; }
MVT::SimpleValueType getVT() const { return VT; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitStringInteger;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
@@ -811,7 +811,7 @@ private:
}
virtual unsigned getHashImpl() const;
};
-
+
/// EmitRegisterMatcher - This creates a new TargetConstant.
class EmitRegisterMatcher : public Matcher {
/// Reg - The def for the register that we're emitting. If this is null, then
@@ -821,14 +821,14 @@ class EmitRegisterMatcher : public Matcher {
public:
EmitRegisterMatcher(Record *reg, MVT::SimpleValueType vt)
: Matcher(EmitRegister), Reg(reg), VT(vt) {}
-
+
Record *getReg() const { return Reg; }
MVT::SimpleValueType getVT() const { return VT; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitRegister;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
@@ -848,13 +848,13 @@ class EmitConvertToTargetMatcher : public Matcher {
public:
EmitConvertToTargetMatcher(unsigned slot)
: Matcher(EmitConvertToTarget), Slot(slot) {}
-
+
unsigned getSlot() const { return Slot; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitConvertToTarget;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
@@ -862,7 +862,7 @@ private:
}
virtual unsigned getHashImpl() const { return Slot; }
};
-
+
/// EmitMergeInputChainsMatcher - Emit a node that merges a list of input
/// chains together with a token factor. The list of nodes are the nodes in the
/// matched pattern that have chain input/outputs. This node adds all input
@@ -872,18 +872,18 @@ class EmitMergeInputChainsMatcher : public Matcher {
public:
EmitMergeInputChainsMatcher(const unsigned *nodes, unsigned NumNodes)
: Matcher(EmitMergeInputChains), ChainNodes(nodes, nodes+NumNodes) {}
-
+
unsigned getNumNodes() const { return ChainNodes.size(); }
-
+
unsigned getNode(unsigned i) const {
assert(i < ChainNodes.size());
return ChainNodes[i];
- }
-
+ }
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitMergeInputChains;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
@@ -891,9 +891,9 @@ private:
}
virtual unsigned getHashImpl() const;
};
-
+
/// EmitCopyToRegMatcher - Emit a CopyToReg node from a value to a physreg,
-/// pushing the chain and flag results.
+/// pushing the chain and glue results.
///
class EmitCopyToRegMatcher : public Matcher {
unsigned SrcSlot; // Value to copy into the physreg.
@@ -901,27 +901,27 @@ class EmitCopyToRegMatcher : public Matcher {
public:
EmitCopyToRegMatcher(unsigned srcSlot, Record *destPhysReg)
: Matcher(EmitCopyToReg), SrcSlot(srcSlot), DestPhysReg(destPhysReg) {}
-
+
unsigned getSrcSlot() const { return SrcSlot; }
Record *getDestPhysReg() const { return DestPhysReg; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitCopyToReg;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
return cast<EmitCopyToRegMatcher>(M)->SrcSlot == SrcSlot &&
- cast<EmitCopyToRegMatcher>(M)->DestPhysReg == DestPhysReg;
+ cast<EmitCopyToRegMatcher>(M)->DestPhysReg == DestPhysReg;
}
virtual unsigned getHashImpl() const {
return SrcSlot ^ ((unsigned)(intptr_t)DestPhysReg << 4);
}
};
-
-
-
+
+
+
/// EmitNodeXFormMatcher - Emit an operation that runs an SDNodeXForm on a
/// recorded node and records the result.
class EmitNodeXFormMatcher : public Matcher {
@@ -930,33 +930,33 @@ class EmitNodeXFormMatcher : public Matcher {
public:
EmitNodeXFormMatcher(unsigned slot, Record *nodeXForm)
: Matcher(EmitNodeXForm), Slot(slot), NodeXForm(nodeXForm) {}
-
+
unsigned getSlot() const { return Slot; }
Record *getNodeXForm() const { return NodeXForm; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitNodeXForm;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
return cast<EmitNodeXFormMatcher>(M)->Slot == Slot &&
- cast<EmitNodeXFormMatcher>(M)->NodeXForm == NodeXForm;
+ cast<EmitNodeXFormMatcher>(M)->NodeXForm == NodeXForm;
}
virtual unsigned getHashImpl() const {
return Slot ^ ((unsigned)(intptr_t)NodeXForm << 4);
}
};
-
+
/// EmitNodeMatcherCommon - Common class shared between EmitNode and
/// MorphNodeTo.
class EmitNodeMatcherCommon : public Matcher {
std::string OpcodeName;
const SmallVector<MVT::SimpleValueType, 3> VTs;
const SmallVector<unsigned, 6> Operands;
- bool HasChain, HasInFlag, HasOutFlag, HasMemRefs;
-
+ bool HasChain, HasInGlue, HasOutGlue, HasMemRefs;
+
/// NumFixedArityOperands - If this is a fixed arity node, this is set to -1.
/// If this is a varidic node, this is set to the number of fixed arity
/// operands in the root of the pattern. The rest are appended to this node.
@@ -965,16 +965,16 @@ public:
EmitNodeMatcherCommon(const std::string &opcodeName,
const MVT::SimpleValueType *vts, unsigned numvts,
const unsigned *operands, unsigned numops,
- bool hasChain, bool hasInFlag, bool hasOutFlag,
+ bool hasChain, bool hasInGlue, bool hasOutGlue,
bool hasmemrefs,
int numfixedarityoperands, bool isMorphNodeTo)
: Matcher(isMorphNodeTo ? MorphNodeTo : EmitNode), OpcodeName(opcodeName),
VTs(vts, vts+numvts), Operands(operands, operands+numops),
- HasChain(hasChain), HasInFlag(hasInFlag), HasOutFlag(hasOutFlag),
+ HasChain(hasChain), HasInGlue(hasInGlue), HasOutGlue(hasOutGlue),
HasMemRefs(hasmemrefs), NumFixedArityOperands(numfixedarityoperands) {}
-
+
const std::string &getOpcodeName() const { return OpcodeName; }
-
+
unsigned getNumVTs() const { return VTs.size(); }
MVT::SimpleValueType getVT(unsigned i) const {
assert(i < VTs.size());
@@ -986,27 +986,27 @@ public:
assert(i < Operands.size());
return Operands[i];
}
-
+
const SmallVectorImpl<MVT::SimpleValueType> &getVTList() const { return VTs; }
const SmallVectorImpl<unsigned> &getOperandList() const { return Operands; }
-
+
bool hasChain() const { return HasChain; }
- bool hasInFlag() const { return HasInFlag; }
- bool hasOutFlag() const { return HasOutFlag; }
+ bool hasInFlag() const { return HasInGlue; }
+ bool hasOutFlag() const { return HasOutGlue; }
bool hasMemRefs() const { return HasMemRefs; }
int getNumFixedArityOperands() const { return NumFixedArityOperands; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitNode || N->getKind() == MorphNodeTo;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const;
virtual unsigned getHashImpl() const;
};
-
+
/// EmitNodeMatcher - This signals a successful match and generates a node.
class EmitNodeMatcher : public EmitNodeMatcherCommon {
unsigned FirstResultSlot;
@@ -1021,15 +1021,15 @@ public:
hasInFlag, hasOutFlag, hasmemrefs,
numfixedarityoperands, false),
FirstResultSlot(firstresultslot) {}
-
+
unsigned getFirstResultSlot() const { return FirstResultSlot; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == EmitNode;
}
-
+
};
-
+
class MorphNodeToMatcher : public EmitNodeMatcherCommon {
const PatternToMatch &Pattern;
public:
@@ -1044,38 +1044,38 @@ public:
numfixedarityoperands, true),
Pattern(pattern) {
}
-
+
const PatternToMatch &getPattern() const { return Pattern; }
static inline bool classof(const Matcher *N) {
return N->getKind() == MorphNodeTo;
}
};
-
-/// MarkFlagResultsMatcher - This node indicates which non-root nodes in the
-/// pattern produce flags. This allows CompleteMatchMatcher to update them
-/// with the output flag of the resultant code.
-class MarkFlagResultsMatcher : public Matcher {
- SmallVector<unsigned, 3> FlagResultNodes;
+
+/// MarkGlueResultsMatcher - This node indicates which non-root nodes in the
+/// pattern produce glue. This allows CompleteMatchMatcher to update them
+/// with the output glue of the resultant code.
+class MarkGlueResultsMatcher : public Matcher {
+ SmallVector<unsigned, 3> GlueResultNodes;
public:
- MarkFlagResultsMatcher(const unsigned *nodes, unsigned NumNodes)
- : Matcher(MarkFlagResults), FlagResultNodes(nodes, nodes+NumNodes) {}
-
- unsigned getNumNodes() const { return FlagResultNodes.size(); }
-
+ MarkGlueResultsMatcher(const unsigned *nodes, unsigned NumNodes)
+ : Matcher(MarkGlueResults), GlueResultNodes(nodes, nodes+NumNodes) {}
+
+ unsigned getNumNodes() const { return GlueResultNodes.size(); }
+
unsigned getNode(unsigned i) const {
- assert(i < FlagResultNodes.size());
- return FlagResultNodes[i];
- }
-
+ assert(i < GlueResultNodes.size());
+ return GlueResultNodes[i];
+ }
+
static inline bool classof(const Matcher *N) {
- return N->getKind() == MarkFlagResults;
+ return N->getKind() == MarkGlueResults;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
- return cast<MarkFlagResultsMatcher>(M)->FlagResultNodes == FlagResultNodes;
+ return cast<MarkGlueResultsMatcher>(M)->GlueResultNodes == GlueResultNodes;
}
virtual unsigned getHashImpl() const;
};
@@ -1095,11 +1095,11 @@ public:
unsigned getNumResults() const { return Results.size(); }
unsigned getResult(unsigned R) const { return Results[R]; }
const PatternToMatch &getPattern() const { return Pattern; }
-
+
static inline bool classof(const Matcher *N) {
return N->getKind() == CompleteMatch;
}
-
+
private:
virtual void printImpl(raw_ostream &OS, unsigned indent) const;
virtual bool isEqualImpl(const Matcher *M) const {
@@ -1108,7 +1108,7 @@ private:
}
virtual unsigned getHashImpl() const;
};
-
+
} // end namespace llvm
#endif
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index dfbfe80c0a1d..0b7fbf7c8518 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -220,8 +220,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << "OPC_RecordMemRef,\n";
return 1;
- case Matcher::CaptureFlagInput:
- OS << "OPC_CaptureFlagInput,\n";
+ case Matcher::CaptureGlueInput:
+ OS << "OPC_CaptureGlueInput,\n";
return 1;
case Matcher::MoveChild:
@@ -485,8 +485,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << ", TARGET_OPCODE(" << EN->getOpcodeName() << "), 0";
if (EN->hasChain()) OS << "|OPFL_Chain";
- if (EN->hasInFlag()) OS << "|OPFL_FlagInput";
- if (EN->hasOutFlag()) OS << "|OPFL_FlagOutput";
+ if (EN->hasInFlag()) OS << "|OPFL_GlueInput";
+ if (EN->hasOutFlag()) OS << "|OPFL_GlueOutput";
if (EN->hasMemRefs()) OS << "|OPFL_MemRefs";
if (EN->getNumFixedArityOperands() != -1)
OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands();
@@ -531,9 +531,9 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
return 6+EN->getNumVTs()+NumOperandBytes;
}
- case Matcher::MarkFlagResults: {
- const MarkFlagResultsMatcher *CFR = cast<MarkFlagResultsMatcher>(N);
- OS << "OPC_MarkFlagResults, " << CFR->getNumNodes() << ", ";
+ case Matcher::MarkGlueResults: {
+ const MarkGlueResultsMatcher *CFR = cast<MarkGlueResultsMatcher>(N);
+ OS << "OPC_MarkGlueResults, " << CFR->getNumNodes() << ", ";
unsigned NumOperandBytes = 0;
for (unsigned i = 0, e = CFR->getNumNodes(); i != e; ++i)
NumOperandBytes += EmitVBRValue(CFR->getNode(i), OS);
@@ -633,8 +633,9 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
// Emit CompletePattern matchers.
// FIXME: This should be const.
if (!ComplexPatterns.empty()) {
- OS << "bool CheckComplexPattern(SDNode *Root, SDValue N,\n";
- OS << " unsigned PatternNo, SmallVectorImpl<SDValue> &Result) {\n";
+ OS << "bool CheckComplexPattern(SDNode *Root, SDNode *Parent, SDValue N,\n";
+ OS << " unsigned PatternNo,\n";
+ OS << " SmallVectorImpl<std::pair<SDValue, SDNode*> > &Result) {\n";
OS << " unsigned NextRes = Result.size();\n";
OS << " switch (PatternNo) {\n";
OS << " default: assert(0 && \"Invalid pattern # in table?\");\n";
@@ -649,9 +650,20 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
OS << " Result.resize(NextRes+" << NumOps << ");\n";
OS << " return " << P.getSelectFunc();
- OS << "(Root, N";
+ OS << "(";
+ // If the complex pattern wants the root of the match, pass it in as the
+ // first argument.
+ if (P.hasProperty(SDNPWantRoot))
+ OS << "Root, ";
+
+ // If the complex pattern wants the parent of the operand being matched,
+ // pass it in as the next argument.
+ if (P.hasProperty(SDNPWantParent))
+ OS << "Parent, ";
+
+ OS << "N";
for (unsigned i = 0; i != NumOps; ++i)
- OS << ", Result[NextRes+" << i << ']';
+ OS << ", Result[NextRes+" << i << "].first";
OS << ");\n";
}
OS << " }\n";
@@ -730,7 +742,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
case Matcher::RecordNode: OS << "OPC_RecordNode"; break;
case Matcher::RecordChild: OS << "OPC_RecordChild"; break;
case Matcher::RecordMemRef: OS << "OPC_RecordMemRef"; break;
- case Matcher::CaptureFlagInput: OS << "OPC_CaptureFlagInput"; break;
+ case Matcher::CaptureGlueInput: OS << "OPC_CaptureGlueInput"; break;
case Matcher::MoveChild: OS << "OPC_MoveChild"; break;
case Matcher::MoveParent: OS << "OPC_MoveParent"; break;
case Matcher::CheckSame: OS << "OPC_CheckSame"; break;
@@ -759,7 +771,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
case Matcher::EmitNode: OS << "OPC_EmitNode"; break;
case Matcher::MorphNodeTo: OS << "OPC_MorphNodeTo"; break;
case Matcher::EmitNodeXForm: OS << "OPC_EmitNodeXForm"; break;
- case Matcher::MarkFlagResults: OS << "OPC_MarkFlagResults"; break;
+ case Matcher::MarkGlueResults: OS << "OPC_MarkGlueResults"; break;
case Matcher::CompleteMatch: OS << "OPC_CompleteMatch"; break;
}
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index aba6636a1370..7c0badec1d6d 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -25,12 +25,12 @@ static MVT::SimpleValueType getRegisterValueType(Record *R,
MVT::SimpleValueType VT = MVT::Other;
const std::vector<CodeGenRegisterClass> &RCs = T.getRegisterClasses();
std::vector<Record*>::const_iterator Element;
-
+
for (unsigned rc = 0, e = RCs.size(); rc != e; ++rc) {
const CodeGenRegisterClass &RC = RCs[rc];
if (!std::count(RC.Elements.begin(), RC.Elements.end(), R))
continue;
-
+
if (!FoundRC) {
FoundRC = true;
VT = RC.getValueTypeNum(0);
@@ -48,30 +48,30 @@ namespace {
class MatcherGen {
const PatternToMatch &Pattern;
const CodeGenDAGPatterns &CGP;
-
+
/// PatWithNoTypes - This is a clone of Pattern.getSrcPattern() that starts
/// out with all of the types removed. This allows us to insert type checks
/// as we scan the tree.
TreePatternNode *PatWithNoTypes;
-
+
/// VariableMap - A map from variable names ('$dst') to the recorded operand
/// number that they were captured as. These are biased by 1 to make
/// insertion easier.
StringMap<unsigned> VariableMap;
-
+
/// NextRecordedOperandNo - As we emit opcodes to record matched values in
/// the RecordedNodes array, this keeps track of which slot will be next to
/// record into.
unsigned NextRecordedOperandNo;
-
+
/// MatchedChainNodes - This maintains the position in the recorded nodes
/// array of all of the recorded input nodes that have chains.
SmallVector<unsigned, 2> MatchedChainNodes;
- /// MatchedFlagResultNodes - This maintains the position in the recorded
- /// nodes array of all of the recorded input nodes that have flag results.
- SmallVector<unsigned, 2> MatchedFlagResultNodes;
-
+ /// MatchedGlueResultNodes - This maintains the position in the recorded
+ /// nodes array of all of the recorded input nodes that have glue results.
+ SmallVector<unsigned, 2> MatchedGlueResultNodes;
+
/// MatchedComplexPatterns - This maintains a list of all of the
/// ComplexPatterns that we need to check. The patterns are known to have
/// names which were recorded. The second element of each pair is the first
@@ -79,40 +79,39 @@ namespace {
/// results into.
SmallVector<std::pair<const TreePatternNode*,
unsigned>, 2> MatchedComplexPatterns;
-
+
/// PhysRegInputs - List list has an entry for each explicitly specified
/// physreg input to the pattern. The first elt is the Register node, the
/// second is the recorded slot number the input pattern match saved it in.
SmallVector<std::pair<Record*, unsigned>, 2> PhysRegInputs;
-
+
/// Matcher - This is the top level of the generated matcher, the result.
Matcher *TheMatcher;
-
+
/// CurPredicate - As we emit matcher nodes, this points to the latest check
/// which should have future checks stuck into its Next position.
Matcher *CurPredicate;
public:
MatcherGen(const PatternToMatch &pattern, const CodeGenDAGPatterns &cgp);
-
+
~MatcherGen() {
delete PatWithNoTypes;
}
-
+
bool EmitMatcherCode(unsigned Variant);
void EmitResultCode();
-
+
Matcher *GetMatcher() const { return TheMatcher; }
- Matcher *GetCurPredicate() const { return CurPredicate; }
private:
void AddMatcher(Matcher *NewNode);
void InferPossibleTypes();
-
+
// Matcher Generation.
void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes);
void EmitLeafMatchCode(const TreePatternNode *N);
void EmitOperatorMatchCode(const TreePatternNode *N,
TreePatternNode *NodeNoTypes);
-
+
// Result Code Generation.
unsigned getNamedArgumentSlot(StringRef Name) {
unsigned VarMapEntry = VariableMap[Name];
@@ -124,7 +123,7 @@ namespace {
/// GetInstPatternNode - Get the pattern for an instruction.
const TreePatternNode *GetInstPatternNode(const DAGInstruction &Ins,
const TreePatternNode *N);
-
+
void EmitResultOperand(const TreePatternNode *N,
SmallVectorImpl<unsigned> &ResultOps);
void EmitResultOfNamedOperand(const TreePatternNode *N,
@@ -136,7 +135,7 @@ namespace {
void EmitResultSDNodeXFormAsOperand(const TreePatternNode *N,
SmallVectorImpl<unsigned> &ResultOps);
};
-
+
} // end anon namespace.
MatcherGen::MatcherGen(const PatternToMatch &pattern,
@@ -157,7 +156,7 @@ MatcherGen::MatcherGen(const PatternToMatch &pattern,
//
PatWithNoTypes = Pattern.getSrcPattern()->clone();
PatWithNoTypes->RemoveAllTypes();
-
+
// If there are types that are manifestly known, infer them.
InferPossibleTypes();
}
@@ -170,7 +169,7 @@ void MatcherGen::InferPossibleTypes() {
// TP - Get *SOME* tree pattern, we don't care which. It is only used for
// diagnostics, which we know are impossible at this point.
TreePattern &TP = *CGP.pf_begin()->second;
-
+
try {
bool MadeChange = true;
while (MadeChange)
@@ -183,7 +182,7 @@ void MatcherGen::InferPossibleTypes() {
}
-/// AddMatcher - Add a matcher node to the current graph we're building.
+/// AddMatcher - Add a matcher node to the current graph we're building.
void MatcherGen::AddMatcher(Matcher *NewNode) {
if (CurPredicate != 0)
CurPredicate->setNext(NewNode);
@@ -200,7 +199,7 @@ void MatcherGen::AddMatcher(Matcher *NewNode) {
/// EmitLeafMatchCode - Generate matching code for leaf nodes.
void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
assert(N->isLeaf() && "Not a leaf?");
-
+
// Direct match against an integer constant.
if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
// If this is the root of the dag we're matching, we emit a redundant opcode
@@ -213,16 +212,16 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
return AddMatcher(new CheckIntegerMatcher(II->getValue()));
}
-
+
DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue());
if (DI == 0) {
errs() << "Unknown leaf kind: " << *DI << "\n";
abort();
}
-
+
Record *LeafRec = DI->getDef();
if (// Handle register references. Nothing to do here, they always match.
- LeafRec->isSubClassOf("RegisterClass") ||
+ LeafRec->isSubClassOf("RegisterClass") ||
LeafRec->isSubClassOf("PointerLikeRegClass") ||
LeafRec->isSubClassOf("SubRegIndex") ||
// Place holder for SRCVALUE nodes. Nothing to do here.
@@ -230,20 +229,20 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
return;
// If we have a physreg reference like (mul gpr:$src, EAX) then we need to
- // record the register
+ // record the register
if (LeafRec->isSubClassOf("Register")) {
AddMatcher(new RecordMatcher("physreg input "+LeafRec->getName(),
NextRecordedOperandNo));
PhysRegInputs.push_back(std::make_pair(LeafRec, NextRecordedOperandNo++));
return;
}
-
+
if (LeafRec->isSubClassOf("ValueType"))
return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName()));
-
+
if (LeafRec->isSubClassOf("CondCode"))
return AddMatcher(new CheckCondCodeMatcher(LeafRec->getName()));
-
+
if (LeafRec->isSubClassOf("ComplexPattern")) {
// We can't model ComplexPattern uses that don't have their name taken yet.
// The OPC_CheckComplexPattern operation implicitly records the results.
@@ -257,7 +256,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
MatchedComplexPatterns.push_back(std::make_pair(N, 0));
return;
}
-
+
errs() << "Unknown leaf kind: " << *N << "\n";
abort();
}
@@ -266,7 +265,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
TreePatternNode *NodeNoTypes) {
assert(!N->isLeaf() && "Not an operator?");
const SDNodeInfo &CInfo = CGP.getSDNodeInfo(N->getOperator());
-
+
// 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
@@ -277,7 +276,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
// 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->getOperator()->getName() == "and" ||
+ if ((N->getOperator()->getName() == "and" ||
N->getOperator()->getName() == "or") &&
N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateFns().empty() &&
N->getPredicateFns().empty()) {
@@ -303,15 +302,15 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
}
}
}
-
+
// Check that the current opcode lines up.
AddMatcher(new CheckOpcodeMatcher(CInfo));
-
+
// If this node has memory references (i.e. is a load or store), tell the
// interpreter to capture them in the memref array.
if (N->NodeHasProperty(SDNPMemOperand, CGP))
AddMatcher(new RecordMemRefMatcher());
-
+
// If this node has a chain, then the chain is operand #0 is the SDNode, and
// the child numbers of the node are all offset by one.
unsigned OpNo = 0;
@@ -322,7 +321,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
NextRecordedOperandNo));
// Remember all of the input chains our pattern will match.
MatchedChainNodes.push_back(NextRecordedOperandNo++);
-
+
// Don't look at the input chain when matching the tree pattern to the
// SDNode.
OpNo = 1;
@@ -353,11 +352,11 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
// If there is a node between the root and this node, then we definitely
// need to emit the check.
bool NeedCheck = !Root->hasChild(N);
-
+
// If it *is* an immediate child of the root, we can still need a check if
// the root SDNode has multiple inputs. For us, this means that it is an
// intrinsic, has multiple operands, or has other inputs like chain or
- // flag).
+ // glue).
if (!NeedCheck) {
const SDNodeInfo &PInfo = CGP.getSDNodeInfo(Root->getOperator());
NeedCheck =
@@ -366,34 +365,34 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
Root->getOperator() == CGP.get_intrinsic_wo_chain_sdnode() ||
PInfo.getNumOperands() > 1 ||
PInfo.hasProperty(SDNPHasChain) ||
- PInfo.hasProperty(SDNPInFlag) ||
- PInfo.hasProperty(SDNPOptInFlag);
+ PInfo.hasProperty(SDNPInGlue) ||
+ PInfo.hasProperty(SDNPOptInGlue);
}
-
+
if (NeedCheck)
AddMatcher(new CheckFoldableChainNodeMatcher());
}
}
- // If this node has an output flag and isn't the root, remember it.
- if (N->NodeHasProperty(SDNPOutFlag, CGP) &&
+ // If this node has an output glue and isn't the root, remember it.
+ if (N->NodeHasProperty(SDNPOutGlue, CGP) &&
N != Pattern.getSrcPattern()) {
- // TODO: This redundantly records nodes with both flags and chains.
-
+ // TODO: This redundantly records nodes with both glues and chains.
+
// Record the node and remember it in our chained nodes list.
AddMatcher(new RecordMatcher("'" + N->getOperator()->getName() +
- "' flag output node",
+ "' glue output node",
NextRecordedOperandNo));
- // Remember all of the nodes with output flags our pattern will match.
- MatchedFlagResultNodes.push_back(NextRecordedOperandNo++);
+ // Remember all of the nodes with output glue our pattern will match.
+ MatchedGlueResultNodes.push_back(NextRecordedOperandNo++);
}
-
- // If this node is known to have an input flag or if it *might* have an input
- // flag, capture it as the flag input of the pattern.
- if (N->NodeHasProperty(SDNPOptInFlag, CGP) ||
- N->NodeHasProperty(SDNPInFlag, CGP))
- AddMatcher(new CaptureFlagInputMatcher());
-
+
+ // If this node is known to have an input glue or if it *might* have an input
+ // glue, capture it as the glue input of the pattern.
+ if (N->NodeHasProperty(SDNPOptInGlue, CGP) ||
+ N->NodeHasProperty(SDNPInGlue, CGP))
+ AddMatcher(new CaptureGlueInputMatcher());
+
for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) {
// Get the code suitable for matching this child. Move to the child, check
// it then move back to the parent.
@@ -410,14 +409,14 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
// need to do a type check. Emit the check, apply the tyep to NodeNoTypes and
// reinfer any correlated types.
SmallVector<unsigned, 2> ResultsToTypeCheck;
-
+
for (unsigned i = 0, e = NodeNoTypes->getNumTypes(); i != e; ++i) {
if (NodeNoTypes->getExtType(i) == N->getExtType(i)) continue;
NodeNoTypes->setType(i, N->getExtType(i));
InferPossibleTypes();
ResultsToTypeCheck.push_back(i);
}
-
+
// 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()) {
@@ -435,16 +434,16 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
return;
}
}
-
+
if (N->isLeaf())
EmitLeafMatchCode(N);
else
EmitOperatorMatchCode(N, NodeNoTypes);
-
+
// If there are node predicates for this node, generate their checks.
for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i)
AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i]));
-
+
for (unsigned i = 0, e = ResultsToTypeCheck.size(); i != e; ++i)
AddMatcher(new CheckTypeMatcher(N->getType(ResultsToTypeCheck[i]),
ResultsToTypeCheck[i]));
@@ -463,27 +462,27 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
const std::vector<Record*> &OpNodes = CP->getRootNodes();
assert(!OpNodes.empty() &&"Complex Pattern must specify what it can match");
if (Variant >= OpNodes.size()) return true;
-
+
AddMatcher(new CheckOpcodeMatcher(CGP.getSDNodeInfo(OpNodes[Variant])));
} else {
if (Variant != 0) return true;
}
-
+
// Emit the matcher for the pattern structure and types.
EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes);
-
+
// If the pattern has a predicate on it (e.g. only enabled when a subtarget
// feature is around, do the check).
if (!Pattern.getPredicateCheck().empty())
AddMatcher(new CheckPatternPredicateMatcher(Pattern.getPredicateCheck()));
-
+
// Now that we've completed the structural type match, emit any ComplexPattern
// checks (e.g. addrmode matches). We emit this after the structural match
// because they are generally more expensive to evaluate and more difficult to
// factor.
for (unsigned i = 0, e = MatchedComplexPatterns.size(); i != e; ++i) {
const TreePatternNode *N = MatchedComplexPatterns[i].first;
-
+
// Remember where the results of this match get stuck.
MatchedComplexPatterns[i].second = NextRecordedOperandNo;
@@ -492,15 +491,15 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
assert(!N->getName().empty() && RecNodeEntry &&
"Complex pattern should have a name and slot");
--RecNodeEntry; // Entries in VariableMap are biased.
-
+
const ComplexPattern &CP =
CGP.getComplexPattern(((DefInit*)N->getLeafValue())->getDef());
-
+
// Emit a CheckComplexPat operation, which does the match (aborting if it
// fails) and pushes the matched operands onto the recorded nodes list.
AddMatcher(new CheckComplexPatMatcher(CP, RecNodeEntry,
N->getName(), NextRecordedOperandNo));
-
+
// Record the right number of operands.
NextRecordedOperandNo += CP.getNumOperands();
if (CP.hasProperty(SDNPHasChain)) {
@@ -508,17 +507,17 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
// fact that we just recorded a chain input. The chain input will be
// matched as the last operand of the predicate if it was successful.
++NextRecordedOperandNo; // Chained node operand.
-
+
// It is the last operand recorded.
assert(NextRecordedOperandNo > 1 &&
"Should have recorded input/result chains at least!");
MatchedChainNodes.push_back(NextRecordedOperandNo-1);
}
-
- // TODO: Complex patterns can't have output flags, if they did, we'd want
+
+ // TODO: Complex patterns can't have output glues, if they did, we'd want
// to record them.
}
-
+
return false;
}
@@ -530,7 +529,7 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N,
SmallVectorImpl<unsigned> &ResultOps){
assert(!N->getName().empty() && "Operand not named!");
-
+
// A reference to a complex pattern gets all of the results of the complex
// pattern's match.
if (const ComplexPattern *CP = N->getComplexPatternInfo(CGP)) {
@@ -541,7 +540,7 @@ void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N,
break;
}
assert(SlotNo != 0 && "Didn't get a slot number assigned?");
-
+
// The first slot entry is the node itself, the subsequent entries are the
// matched values.
for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i)
@@ -562,20 +561,20 @@ void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N,
return;
}
}
-
+
ResultOps.push_back(SlotNo);
}
void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
SmallVectorImpl<unsigned> &ResultOps) {
assert(N->isLeaf() && "Must be a leaf");
-
+
if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
-
+
// If this is an explicit register reference, handle it.
if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
if (DI->getDef()->isSubClassOf("Register")) {
@@ -583,13 +582,13 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
-
+
if (DI->getDef()->getName() == "zero_reg") {
AddMatcher(new EmitRegisterMatcher(0, N->getType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
-
+
// Handle a reference to a register class. This is used
// in COPY_TO_SUBREG instructions.
if (DI->getDef()->isSubClassOf("RegisterClass")) {
@@ -607,17 +606,17 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
return;
}
}
-
+
errs() << "unhandled leaf node: \n";
N->dump();
}
/// GetInstPatternNode - Get the pattern for an instruction.
-///
+///
const TreePatternNode *MatcherGen::
GetInstPatternNode(const DAGInstruction &Inst, const TreePatternNode *N) {
const TreePattern *InstPat = Inst.getPattern();
-
+
// FIXME2?: Assume actual pattern comes before "implicit".
TreePatternNode *InstPatNode;
if (InstPat)
@@ -626,11 +625,11 @@ GetInstPatternNode(const DAGInstruction &Inst, const TreePatternNode *N) {
InstPatNode = Pattern.getSrcPattern();
else
return 0;
-
+
if (InstPatNode && !InstPatNode->isLeaf() &&
InstPatNode->getOperator()->getName() == "set")
InstPatNode = InstPatNode->getChild(InstPatNode->getNumChildren()-1);
-
+
return InstPatNode;
}
@@ -641,7 +640,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
const CodeGenTarget &CGT = CGP.getTargetInfo();
CodeGenInstruction &II = CGT.getInstruction(Op);
const DAGInstruction &Inst = CGP.getInstruction(Op);
-
+
// If we can, get the pattern for the instruction we're generating. We derive
// a variety of information from this pattern, such as whether it has a chain.
//
@@ -650,27 +649,27 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// nodes can't duplicate.
const TreePatternNode *InstPatNode = GetInstPatternNode(Inst, N);
- // NodeHasChain - Whether the instruction node we're creating takes chains.
+ // NodeHasChain - Whether the instruction node we're creating takes chains.
bool NodeHasChain = InstPatNode &&
InstPatNode->TreeHasProperty(SDNPHasChain, CGP);
-
+
bool isRoot = N == Pattern.getDstPattern();
- // TreeHasOutFlag - True if this tree has a flag.
- bool TreeHasInFlag = false, TreeHasOutFlag = false;
+ // TreeHasOutGlue - True if this tree has glue.
+ bool TreeHasInGlue = false, TreeHasOutGlue = false;
if (isRoot) {
const TreePatternNode *SrcPat = Pattern.getSrcPattern();
- TreeHasInFlag = SrcPat->TreeHasProperty(SDNPOptInFlag, CGP) ||
- SrcPat->TreeHasProperty(SDNPInFlag, CGP);
-
+ TreeHasInGlue = SrcPat->TreeHasProperty(SDNPOptInGlue, CGP) ||
+ SrcPat->TreeHasProperty(SDNPInGlue, CGP);
+
// FIXME2: this is checking the entire pattern, not just the node in
// question, doing this just for the root seems like a total hack.
- TreeHasOutFlag = SrcPat->TreeHasProperty(SDNPOutFlag, CGP);
+ TreeHasOutGlue = SrcPat->TreeHasProperty(SDNPOutGlue, CGP);
}
// NumResults - This is the number of results produced by the instruction in
// the "outs" list.
- unsigned NumResults = Inst.getNumResults();
+ unsigned NumResults = Inst.getNumResults();
// 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
@@ -679,41 +678,41 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// in the 'execute always' values. Match up the node operands to the
// instruction operands to do this.
SmallVector<unsigned, 8> InstOps;
- for (unsigned ChildNo = 0, InstOpNo = NumResults, e = II.OperandList.size();
+ for (unsigned ChildNo = 0, InstOpNo = NumResults, e = II.Operands.size();
InstOpNo != e; ++InstOpNo) {
-
+
// Determine what to emit for this operand.
- Record *OperandNode = II.OperandList[InstOpNo].Rec;
+ Record *OperandNode = II.Operands[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(OperandNode);
+ = CGP.getDefaultOperand(OperandNode);
for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i)
EmitResultOperand(DefaultOp.DefaultOps[i], InstOps);
continue;
}
-
+
const TreePatternNode *Child = N->getChild(ChildNo);
-
+
// Otherwise this is a normal operand or a predicate operand without
// 'execute always'; emit it.
unsigned BeforeAddingNumOps = InstOps.size();
EmitResultOperand(Child, InstOps);
assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands");
-
+
// If the operand is an instruction and it produced multiple results, just
// take the first one.
if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction"))
InstOps.resize(BeforeAddingNumOps+1);
-
+
++ChildNo;
}
-
- // If this node has an input flag or explicitly specified input physregs, we
- // need to add chained and flagged copyfromreg nodes and materialize the flag
+
+ // If this node has input glue or explicitly specified input physregs, we
+ // need to add chained and glued copyfromreg nodes and materialize the glue
// input.
if (isRoot && !PhysRegInputs.empty()) {
// Emit all of the CopyToReg nodes for the input physical registers. These
@@ -721,18 +720,18 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i)
AddMatcher(new EmitCopyToRegMatcher(PhysRegInputs[i].second,
PhysRegInputs[i].first));
- // Even if the node has no other flag inputs, the resultant node must be
- // flagged to the CopyFromReg nodes we just generated.
- TreeHasInFlag = true;
+ // Even if the node has no other glue inputs, the resultant node must be
+ // glued to the CopyFromReg nodes we just generated.
+ TreeHasInGlue = true;
}
-
- // Result order: node results, chain, flags
-
+
+ // Result order: node results, chain, glue
+
// Determine the result types.
SmallVector<MVT::SimpleValueType, 4> ResultVTs;
for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i)
ResultVTs.push_back(N->getType(i));
-
+
// If this is the root instruction of a pattern that has physical registers in
// its result pattern, add output VTs for them. For example, X86 has:
// (set AL, (mul ...))
@@ -744,7 +743,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
Record *HandledReg = 0;
if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other)
HandledReg = II.ImplicitDefs[0];
-
+
for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) {
Record *Reg = Pattern.getDstRegs()[i];
if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue;
@@ -759,7 +758,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
if (isRoot &&
(Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP)))
NumFixedArityOperands = Pattern.getSrcPattern()->getNumChildren();
-
+
// If this is the root node and any of the nodes matched nodes in the input
// pattern have MemRefs in them, have the interpreter collect them and plop
// them onto this node.
@@ -776,19 +775,19 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
bool NodeHasMemRefs =
isRoot && Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP);
- assert((!ResultVTs.empty() || TreeHasOutFlag || NodeHasChain) &&
+ assert((!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) &&
"Node has no result");
-
+
AddMatcher(new EmitNodeMatcher(II.Namespace+"::"+II.TheDef->getName(),
ResultVTs.data(), ResultVTs.size(),
InstOps.data(), InstOps.size(),
- NodeHasChain, TreeHasInFlag, TreeHasOutFlag,
+ NodeHasChain, TreeHasInGlue, TreeHasOutGlue,
NodeHasMemRefs, NumFixedArityOperands,
NextRecordedOperandNo));
-
- // The non-chain and non-flag results of the newly emitted node get recorded.
+
+ // The non-chain and non-glue results of the newly emitted node get recorded.
for (unsigned i = 0, e = ResultVTs.size(); i != e; ++i) {
- if (ResultVTs[i] == MVT::Other || ResultVTs[i] == MVT::Flag) break;
+ if (ResultVTs[i] == MVT::Other || ResultVTs[i] == MVT::Glue) break;
OutputOps.push_back(NextRecordedOperandNo++);
}
}
@@ -800,7 +799,7 @@ EmitResultSDNodeXFormAsOperand(const TreePatternNode *N,
// Emit the operand.
SmallVector<unsigned, 8> InputOps;
-
+
// FIXME2: Could easily generalize this to support multiple inputs and outputs
// to the SDNodeXForm. For now we just support one input and one output like
// the old instruction selector.
@@ -839,7 +838,7 @@ void MatcherGen::EmitResultCode() {
if (!MatchedChainNodes.empty())
AddMatcher(new EmitMergeInputChainsMatcher
(MatchedChainNodes.data(), MatchedChainNodes.size()));
-
+
// Codegen the root of the result pattern, capturing the resulting values.
SmallVector<unsigned, 8> Ops;
EmitResultOperand(Pattern.getDstPattern(), Ops);
@@ -847,11 +846,11 @@ void MatcherGen::EmitResultCode() {
// At this point, we have however many values the result pattern produces.
// However, the input pattern might not need all of these. If there are
// excess values at the end (such as implicit defs of condition codes etc)
- // just lop them off. This doesn't need to worry about flags or chains, just
+ // just lop them off. This doesn't need to worry about glue or chains, just
// explicit results.
//
unsigned NumSrcResults = Pattern.getSrcPattern()->getNumTypes();
-
+
// If the pattern also has (implicit) results, count them as well.
if (!Pattern.getDstRegs().empty()) {
// If the root came from an implicit def in the instruction handling stuff,
@@ -865,23 +864,23 @@ void MatcherGen::EmitResultCode() {
if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other)
HandledReg = II.ImplicitDefs[0];
}
-
+
for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) {
Record *Reg = Pattern.getDstRegs()[i];
if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue;
++NumSrcResults;
}
- }
-
+ }
+
assert(Ops.size() >= NumSrcResults && "Didn't provide enough results");
Ops.resize(NumSrcResults);
- // If the matched pattern covers nodes which define a flag result, emit a node
+ // If the matched pattern covers nodes which define a glue result, emit a node
// that tells the matcher about them so that it can update their results.
- if (!MatchedFlagResultNodes.empty())
- AddMatcher(new MarkFlagResultsMatcher(MatchedFlagResultNodes.data(),
- MatchedFlagResultNodes.size()));
-
+ if (!MatchedGlueResultNodes.empty())
+ AddMatcher(new MarkGlueResultsMatcher(MatchedGlueResultNodes.data(),
+ MatchedGlueResultNodes.size()));
+
AddMatcher(new CompleteMatchMatcher(Ops.data(), Ops.size(), Pattern));
}
@@ -896,12 +895,12 @@ Matcher *llvm::ConvertPatternToMatcher(const PatternToMatch &Pattern,
// Generate the code for the matcher.
if (Gen.EmitMatcherCode(Variant))
return 0;
-
+
// FIXME2: Kill extra MoveParent commands at the end of the matcher sequence.
// FIXME2: Split result code out to another table, and make the matcher end
// with an "Emit <index>" command. This allows result generation stuff to be
// shared and factored?
-
+
// If the match succeeds, then we generate Pattern.
Gen.EmitResultCode();
diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp
index c73bdb9efb68..3169ea1e16af 100644
--- a/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -75,7 +75,7 @@ static void ContractNodes(OwningPtr<Matcher> &MatcherPtr,
// MarkFlagResults->EmitNode->CompleteMatch when we can to encourage
// MorphNodeTo formation. This is safe because MarkFlagResults never refers
// to the root of the pattern.
- if (isa<EmitNodeMatcher>(N) && isa<MarkFlagResultsMatcher>(N->getNext()) &&
+ if (isa<EmitNodeMatcher>(N) && isa<MarkGlueResultsMatcher>(N->getNext()) &&
isa<CompleteMatchMatcher>(N->getNext()->getNext())) {
// Unlink the two nodes from the list.
Matcher *EmitNode = MatcherPtr.take();
@@ -100,7 +100,7 @@ static void ContractNodes(OwningPtr<Matcher> &MatcherPtr,
if (CM->getResult(i) != RootResultFirst+i)
ResultsMatch = false;
- // If the selected node defines a subset of the flag/chain results, we
+ // If the selected node defines a subset of the glue/chain results, we
// can't use MorphNodeTo. For example, we can't use MorphNodeTo if the
// matched pattern has a chain but the root node doesn't.
const PatternToMatch &Pattern = CM->getPattern();
@@ -109,23 +109,23 @@ static void ContractNodes(OwningPtr<Matcher> &MatcherPtr,
Pattern.getSrcPattern()->NodeHasProperty(SDNPHasChain, CGP))
ResultsMatch = false;
- // If the matched node has a flag and the output root doesn't, we can't
+ // If the matched node has glue and the output root doesn't, we can't
// use MorphNodeTo.
//
- // NOTE: Strictly speaking, we don't have to check for the flag here
+ // NOTE: Strictly speaking, we don't have to check for glue here
// because the code in the pattern generator doesn't handle it right. We
// do it anyway for thoroughness.
if (!EN->hasOutFlag() &&
- Pattern.getSrcPattern()->NodeHasProperty(SDNPOutFlag, CGP))
+ Pattern.getSrcPattern()->NodeHasProperty(SDNPOutGlue, CGP))
ResultsMatch = false;
// If the root result node defines more results than the source root node
- // *and* has a chain or flag input, then we can't match it because it
- // would end up replacing the extra result with the chain/flag.
+ // *and* has a chain or glue input, then we can't match it because it
+ // would end up replacing the extra result with the chain/glue.
#if 0
- if ((EN->hasFlag() || EN->hasChain()) &&
- EN->getNumNonChainFlagVTs() > ... need to get no results reliably ...)
+ if ((EN->hasGlue() || EN->hasChain()) &&
+ EN->getNumNonChainGlueVTs() > ... need to get no results reliably ...)
ResultMatch = false;
#endif
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index 3284366c6dd8..90a2af21f3a4 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -13,6 +13,7 @@
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
#include "ARMDecoderEmitter.h"
+#include "FixedLenDecoderEmitter.h"
using namespace llvm;
using namespace llvm::X86Disassembler;
@@ -94,7 +95,7 @@ using namespace llvm::X86Disassembler;
/// instruction.
void DisassemblerEmitter::run(raw_ostream &OS) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
OS << "/*===- TableGen'erated file "
<< "---------------------------------------*- C -*-===*\n"
@@ -127,11 +128,11 @@ void DisassemblerEmitter::run(raw_ostream &OS) {
}
// Fixed-instruction-length targets use a common disassembler.
+ // ARM use its own implementation for now.
if (Target.getName() == "ARM") {
ARMDecoderEmitter(Records).run(OS);
return;
}
- throw TGError(Target.getTargetRecord()->getLoc(),
- "Unable to generate disassembler for this target");
+ FixedLenDecoderEmitter(Records).run(OS);
}
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index 525fffb0ee2c..020a4a312d7b 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -35,22 +35,22 @@ using namespace llvm;
///////////////////////////////////////////////////////////
namespace {
-
+
class EnumEmitter {
private:
std::string Name;
std::vector<std::string> Entries;
public:
- EnumEmitter(const char *N) : Name(N) {
+ EnumEmitter(const char *N) : Name(N) {
}
- int addEntry(const char *e) {
+ int addEntry(const char *e) {
Entries.push_back(std::string(e));
- return Entries.size() - 1;
+ return Entries.size() - 1;
}
void emit(raw_ostream &o, unsigned int &i) {
o.indent(i) << "enum " << Name.c_str() << " {" << "\n";
i += 2;
-
+
unsigned int index = 0;
unsigned int numEntries = Entries.size();
for (index = 0; index < numEntries; ++index) {
@@ -59,15 +59,15 @@ namespace {
o << ",";
o << "\n";
}
-
+
i -= 2;
o.indent(i) << "};" << "\n";
}
-
+
void emitAsFlags(raw_ostream &o, unsigned int &i) {
o.indent(i) << "enum " << Name.c_str() << " {" << "\n";
i += 2;
-
+
unsigned int index = 0;
unsigned int numEntries = Entries.size();
unsigned int flag = 1;
@@ -78,7 +78,7 @@ namespace {
o << "\n";
flag <<= 1;
}
-
+
i -= 2;
o.indent(i) << "};" << "\n";
}
@@ -89,7 +89,7 @@ namespace {
virtual ~ConstantEmitter() { }
virtual void emit(raw_ostream &o, unsigned int &i) = 0;
};
-
+
class LiteralConstantEmitter : public ConstantEmitter {
private:
bool IsNumber;
@@ -98,7 +98,7 @@ namespace {
const char* String;
};
public:
- LiteralConstantEmitter(int number = 0) :
+ LiteralConstantEmitter(int number = 0) :
IsNumber(true),
Number(number) {
}
@@ -117,7 +117,7 @@ namespace {
o << String;
}
};
-
+
class CompoundConstantEmitter : public ConstantEmitter {
private:
unsigned int Padding;
@@ -127,7 +127,7 @@ namespace {
}
CompoundConstantEmitter &addEntry(ConstantEmitter *e) {
Entries.push_back(e);
-
+
return *this;
}
~CompoundConstantEmitter() {
@@ -140,12 +140,12 @@ namespace {
void emit(raw_ostream &o, unsigned int &i) {
o << "{" << "\n";
i += 2;
-
+
unsigned int index;
unsigned int numEntries = Entries.size();
-
+
unsigned int numToPrint;
-
+
if (Padding) {
if (numEntries > Padding) {
fprintf(stderr, "%u entries but %u padding\n", numEntries, Padding);
@@ -155,24 +155,24 @@ namespace {
} else {
numToPrint = numEntries;
}
-
+
for (index = 0; index < numToPrint; ++index) {
o.indent(i);
if (index < numEntries)
Entries[index]->emit(o, i);
else
o << "-1";
-
+
if (index < (numToPrint - 1))
o << ",";
o << "\n";
}
-
+
i -= 2;
o.indent(i) << "}";
}
};
-
+
class FlagsConstantEmitter : public ConstantEmitter {
private:
std::vector<std::string> Flags;
@@ -188,7 +188,7 @@ namespace {
unsigned int numFlags = Flags.size();
if (numFlags == 0)
o << "0";
-
+
for (index = 0; index < numFlags; ++index) {
o << Flags[index].c_str();
if (index < (numFlags - 1))
@@ -218,15 +218,15 @@ void populateOperandOrder(CompoundConstantEmitter *operandOrder,
const CodeGenInstruction &inst,
unsigned syntax) {
unsigned int numArgs = 0;
-
+
AsmWriterInst awInst(inst, syntax, -1, -1);
-
+
std::vector<AsmWriterOperand>::iterator operandIterator;
-
+
for (operandIterator = awInst.Operands.begin();
operandIterator != awInst.Operands.end();
++operandIterator) {
- if (operandIterator->OperandType ==
+ if (operandIterator->OperandType ==
AsmWriterOperand::isMachineInstrOperand) {
operandOrder->addEntry(
new LiteralConstantEmitter(operandIterator->CGIOpNo));
@@ -274,7 +274,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
REG("SEGMENT_REG");
REG("DEBUG_REG");
REG("CONTROL_REG");
-
+
IMM("i8imm");
IMM("i16imm");
IMM("i16i8imm");
@@ -284,7 +284,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
IMM("i64i8imm");
IMM("i64i32imm");
IMM("SSECC");
-
+
// all R, I, R, I, R
MEM("i8mem");
MEM("i8mem_NOREX");
@@ -306,12 +306,12 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
MEM("f128mem");
MEM("f256mem");
MEM("opaque512mem");
-
+
// all R, I, R, I
LEA("lea32mem");
LEA("lea64_32mem");
LEA("lea64mem");
-
+
// all I
PCR("i16imm_pcrel");
PCR("i32imm_pcrel");
@@ -322,7 +322,12 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
PCR("offset32");
PCR("offset64");
PCR("brtarget");
-
+ PCR("uncondbrtarget");
+ PCR("bltarget");
+
+ // all I, ARM mode only, conditional/unconditional
+ PCR("br_target");
+ PCR("bl_target");
return 1;
}
@@ -344,19 +349,19 @@ static void X86PopulateOperands(
const CodeGenInstruction &inst) {
if (!inst.TheDef->isSubClassOf("X86Inst"))
return;
-
+
unsigned int index;
- unsigned int numOperands = inst.OperandList.size();
-
+ unsigned int numOperands = inst.Operands.size();
+
for (index = 0; index < numOperands; ++index) {
- const CodeGenInstruction::OperandInfo &operandInfo =
- inst.OperandList[index];
+ const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index];
Record &rec = *operandInfo.Rec;
-
- if (X86TypeFromOpName(operandTypes[index], rec.getName())) {
+
+ if (X86TypeFromOpName(operandTypes[index], rec.getName()) &&
+ !rec.isSubClassOf("PointerLikeRegClass")) {
errs() << "Operand type: " << rec.getName().c_str() << "\n";
errs() << "Operand name: " << operandInfo.Name.c_str() << "\n";
- errs() << "Instruction mame: " << inst.TheDef->getName().c_str() << "\n";
+ errs() << "Instruction name: " << inst.TheDef->getName().c_str() << "\n";
llvm_unreachable("Unhandled type");
}
}
@@ -375,9 +380,9 @@ static inline void decorate1(
const char *opName,
const char *opFlag) {
unsigned opIndex;
-
- opIndex = inst.getOperandNamed(std::string(opName));
-
+
+ opIndex = inst.Operands.getOperandNamed(std::string(opName));
+
operandFlags[opIndex]->addEntry(opFlag);
}
@@ -414,7 +419,7 @@ static inline void decorate1(
}
/// X86ExtractSemantics - Performs various checks on the name of an X86
-/// instruction to determine what sort of an instruction it is and then adds
+/// instruction to determine what sort of an instruction it is and then adds
/// the appropriate flags to the instruction and its operands
///
/// @arg instType - A reference to the type for the instruction as a whole
@@ -425,7 +430,7 @@ static void X86ExtractSemantics(
FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
const CodeGenInstruction &inst) {
const std::string &name = inst.TheDef->getName();
-
+
if (name.find("MOV") != name.npos) {
if (name.find("MOV_V") != name.npos) {
// ignore (this is a pseudoinstruction)
@@ -450,7 +455,7 @@ static void X86ExtractSemantics(
MOV("src", "dst");
}
}
-
+
if (name.find("JMP") != name.npos ||
name.find("J") == 0) {
if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
@@ -459,10 +464,14 @@ static void X86ExtractSemantics(
BRANCH("dst");
}
}
-
+
if (name.find("PUSH") != name.npos) {
- if (name.find("FS") != name.npos ||
- name.find("GS") != name.npos) {
+ if (name.find("CS") != name.npos ||
+ name.find("DS") != name.npos ||
+ name.find("ES") != name.npos ||
+ name.find("FS") != name.npos ||
+ name.find("GS") != name.npos ||
+ name.find("SS") != name.npos) {
instType.set("kInstructionTypePush");
// TODO add support for fixed operands
} else if (name.find("F") != name.npos) {
@@ -477,12 +486,16 @@ static void X86ExtractSemantics(
PUSH("reg");
}
}
-
+
if (name.find("POP") != name.npos) {
if (name.find("POPCNT") != name.npos) {
// ignore (not a real pop)
- } else if (name.find("FS") != name.npos ||
- name.find("GS") != name.npos) {
+ } else if (name.find("CS") != name.npos ||
+ name.find("DS") != name.npos ||
+ name.find("ES") != name.npos ||
+ name.find("FS") != name.npos ||
+ name.find("GS") != name.npos ||
+ name.find("SS") != name.npos) {
instType.set("kInstructionTypePop");
// TODO add support for fixed operands
} else if (name.find("F") != name.npos) {
@@ -495,7 +508,7 @@ static void X86ExtractSemantics(
POP("reg");
}
}
-
+
if (name.find("CALL") != name.npos) {
if (name.find("ADJ") != name.npos) {
// ignore (not a call)
@@ -509,7 +522,7 @@ static void X86ExtractSemantics(
CALL("dst");
}
}
-
+
if (name.find("RET") != name.npos) {
RETURN();
}
@@ -553,12 +566,20 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
REG("QPR");
REG("QQPR");
REG("QQQQPR");
-
+
IMM("i32imm");
+ IMM("i32imm_hilo16");
IMM("bf_inv_mask_imm");
+ IMM("lsb_pos_imm");
+ IMM("width_imm");
IMM("jtblock_operand");
IMM("nohash_imm");
+ IMM("p_imm");
+ IMM("c_imm");
+ IMM("imod_op");
+ IMM("iflags_op");
IMM("cpinst_operand");
+ IMM("setend_op");
IMM("cps_opt");
IMM("vfp_f64imm");
IMM("vfp_f32imm");
@@ -566,46 +587,73 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
IMM("msr_mask");
IMM("neg_zero");
IMM("imm0_31");
+ IMM("imm0_31_m1");
IMM("nModImm");
IMM("imm0_4095");
IMM("jt2block_operand");
IMM("t_imm_s4");
IMM("pclabel");
+ IMM("adrlabel");
+ IMM("t_adrlabel");
+ IMM("t2adrlabel");
IMM("shift_imm");
-
+ IMM("neon_vcvt_imm32");
+
MISC("brtarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("uncondbrtarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("t_brtarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("t_bcctarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("t_cbtarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("bltarget", "kOperandTypeARMBranchTarget"); // ?
+
+ MISC("br_target", "kOperandTypeARMBranchTarget"); // ?
+ MISC("bl_target", "kOperandTypeARMBranchTarget"); // ?
+
+ MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ?
MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I
+ MISC("shift_so_reg", "kOperandTypeARMSoReg"); // R, R, I
MISC("t2_so_reg", "kOperandTypeThumb2SoReg"); // R, I
MISC("so_imm", "kOperandTypeARMSoImm"); // I
+ MISC("rot_imm", "kOperandTypeARMRotImm"); // I
MISC("t2_so_imm", "kOperandTypeThumb2SoImm"); // I
MISC("so_imm2part", "kOperandTypeARMSoImm2Part"); // I
MISC("pred", "kOperandTypeARMPredicate"); // I, R
MISC("it_pred", "kOperandTypeARMPredicate"); // I
+ MISC("addrmode_imm12", "kOperandTypeAddrModeImm12"); // R, I
+ MISC("ldst_so_reg", "kOperandTypeLdStSOReg"); // R, R, I
MISC("addrmode2", "kOperandTypeARMAddrMode2"); // R, R, I
MISC("am2offset", "kOperandTypeARMAddrMode2Offset"); // R, I
MISC("addrmode3", "kOperandTypeARMAddrMode3"); // R, R, I
MISC("am3offset", "kOperandTypeARMAddrMode3Offset"); // R, I
- MISC("addrmode4", "kOperandTypeARMAddrMode4"); // R, I
+ MISC("ldstm_mode", "kOperandTypeARMLdStmMode"); // I
MISC("addrmode5", "kOperandTypeARMAddrMode5"); // R, I
MISC("addrmode6", "kOperandTypeARMAddrMode6"); // R, R, I, I
MISC("am6offset", "kOperandTypeARMAddrMode6Offset"); // R, I, I
+ MISC("addrmode6dup", "kOperandTypeARMAddrMode6"); // R, R, I, I
MISC("addrmodepc", "kOperandTypeARMAddrModePC"); // R, I
MISC("reglist", "kOperandTypeARMRegisterList"); // I, R, ...
+ MISC("dpr_reglist", "kOperandTypeARMDPRRegisterList"); // I, R, ...
+ MISC("spr_reglist", "kOperandTypeARMSPRRegisterList"); // I, R, ...
MISC("it_mask", "kOperandTypeThumbITMask"); // I
MISC("t2addrmode_imm8", "kOperandTypeThumb2AddrModeImm8"); // R, I
MISC("t2am_imm8_offset", "kOperandTypeThumb2AddrModeImm8Offset");//I
MISC("t2addrmode_imm12", "kOperandTypeThumb2AddrModeImm12"); // R, I
MISC("t2addrmode_so_reg", "kOperandTypeThumb2AddrModeSoReg"); // R, R, I
MISC("t2addrmode_imm8s4", "kOperandTypeThumb2AddrModeImm8s4"); // R, I
- MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset");
+ MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset");
// R, I
MISC("tb_addrmode", "kOperandTypeARMTBAddrMode"); // I
- MISC("t_addrmode_s1", "kOperandTypeThumbAddrModeS1"); // R, I, R
- MISC("t_addrmode_s2", "kOperandTypeThumbAddrModeS2"); // R, I, R
- MISC("t_addrmode_s4", "kOperandTypeThumbAddrModeS4"); // R, I, R
+ MISC("t_addrmode_rrs1", "kOperandTypeThumbAddrModeRegS"); // R, R
+ MISC("t_addrmode_rrs2", "kOperandTypeThumbAddrModeRegS"); // R, R
+ MISC("t_addrmode_rrs4", "kOperandTypeThumbAddrModeRegS"); // R, R
+ MISC("t_addrmode_is1", "kOperandTypeThumbAddrModeImmS"); // R, I
+ MISC("t_addrmode_is2", "kOperandTypeThumbAddrModeImmS"); // R, I
+ MISC("t_addrmode_is4", "kOperandTypeThumbAddrModeImmS"); // R, I
MISC("t_addrmode_rr", "kOperandTypeThumbAddrModeRR"); // R, R
MISC("t_addrmode_sp", "kOperandTypeThumbAddrModeSP"); // R, I
-
+ MISC("t_addrmode_pc", "kOperandTypeThumbAddrModePC"); // R, I
+
return 1;
}
@@ -631,25 +679,24 @@ static void ARMPopulateOperands(
if (!inst.TheDef->isSubClassOf("InstARM") &&
!inst.TheDef->isSubClassOf("InstThumb"))
return;
-
+
unsigned int index;
- unsigned int numOperands = inst.OperandList.size();
-
+ unsigned int numOperands = inst.Operands.size();
+
if (numOperands > EDIS_MAX_OPERANDS) {
- errs() << "numOperands == " << numOperands << " > " <<
+ errs() << "numOperands == " << numOperands << " > " <<
EDIS_MAX_OPERANDS << '\n';
llvm_unreachable("Too many operands");
}
-
+
for (index = 0; index < numOperands; ++index) {
- const CodeGenInstruction::OperandInfo &operandInfo =
- inst.OperandList[index];
+ const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index];
Record &rec = *operandInfo.Rec;
-
+
if (ARMFlagFromOpName(operandTypes[index], rec.getName())) {
errs() << "Operand type: " << rec.getName() << '\n';
errs() << "Operand name: " << operandInfo.Name << '\n';
- errs() << "Instruction mame: " << inst.TheDef->getName() << '\n';
+ errs() << "Instruction name: " << inst.TheDef->getName() << '\n';
llvm_unreachable("Unhandled type");
}
}
@@ -661,7 +708,7 @@ static void ARMPopulateOperands(
}
/// ARMExtractSemantics - Performs various checks on the name of an ARM
-/// instruction to determine what sort of an instruction it is and then adds
+/// instruction to determine what sort of an instruction it is and then adds
/// the appropriate flags to the instruction and its operands
///
/// @arg instType - A reference to the type for the instruction as a whole
@@ -674,7 +721,7 @@ static void ARMExtractSemantics(
FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
const CodeGenInstruction &inst) {
const std::string &name = inst.TheDef->getName();
-
+
if (name == "tBcc" ||
name == "tB" ||
name == "t2Bcc" ||
@@ -683,7 +730,7 @@ static void ARMExtractSemantics(
name == "tCBNZ") {
BRANCH("target");
}
-
+
if (name == "tBLr9" ||
name == "BLr9_pred" ||
name == "tBLXi_r9" ||
@@ -692,9 +739,9 @@ static void ARMExtractSemantics(
name == "t2BXJ" ||
name == "BXJ") {
BRANCH("func");
-
+
unsigned opIndex;
- opIndex = inst.getOperandNamed("func");
+ opIndex = inst.Operands.getOperandNamed("func");
if (operandTypes[opIndex]->is("kOperandTypeImmediate"))
operandTypes[opIndex]->set("kOperandTypeARMBranchTarget");
}
@@ -702,7 +749,7 @@ static void ARMExtractSemantics(
#undef BRANCH
-/// populateInstInfo - Fills an array of InstInfos with information about each
+/// populateInstInfo - Fills an array of InstInfos with information about each
/// instruction in a target
///
/// @arg infoArray - The array of InstInfo objects to populate
@@ -711,45 +758,45 @@ static void populateInstInfo(CompoundConstantEmitter &infoArray,
CodeGenTarget &target) {
const std::vector<const CodeGenInstruction*> &numberedInstructions =
target.getInstructionsByEnumValue();
-
+
unsigned int index;
unsigned int numInstructions = numberedInstructions.size();
-
+
for (index = 0; index < numInstructions; ++index) {
const CodeGenInstruction& inst = *numberedInstructions[index];
-
+
CompoundConstantEmitter *infoStruct = new CompoundConstantEmitter;
infoArray.addEntry(infoStruct);
-
+
LiteralConstantEmitter *instType = new LiteralConstantEmitter;
infoStruct->addEntry(instType);
-
- LiteralConstantEmitter *numOperandsEmitter =
- new LiteralConstantEmitter(inst.OperandList.size());
+
+ LiteralConstantEmitter *numOperandsEmitter =
+ new LiteralConstantEmitter(inst.Operands.size());
infoStruct->addEntry(numOperandsEmitter);
-
+
CompoundConstantEmitter *operandTypeArray = new CompoundConstantEmitter;
infoStruct->addEntry(operandTypeArray);
-
+
LiteralConstantEmitter *operandTypes[EDIS_MAX_OPERANDS];
-
+
CompoundConstantEmitter *operandFlagArray = new CompoundConstantEmitter;
infoStruct->addEntry(operandFlagArray);
-
+
FlagsConstantEmitter *operandFlags[EDIS_MAX_OPERANDS];
-
- for (unsigned operandIndex = 0;
- operandIndex < EDIS_MAX_OPERANDS;
+
+ for (unsigned operandIndex = 0;
+ operandIndex < EDIS_MAX_OPERANDS;
++operandIndex) {
operandTypes[operandIndex] = new LiteralConstantEmitter;
operandTypeArray->addEntry(operandTypes[operandIndex]);
-
+
operandFlags[operandIndex] = new FlagsConstantEmitter;
operandFlagArray->addEntry(operandFlags[operandIndex]);
}
-
+
unsigned numSyntaxes = 0;
-
+
if (target.getName() == "X86") {
X86PopulateOperands(operandTypes, inst);
X86ExtractSemantics(*instType, operandFlags, inst);
@@ -760,24 +807,24 @@ static void populateInstInfo(CompoundConstantEmitter &infoArray,
ARMExtractSemantics(*instType, operandTypes, operandFlags, inst);
numSyntaxes = 1;
}
-
- CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter;
-
+
+ CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter;
+
infoStruct->addEntry(operandOrderArray);
-
- for (unsigned syntaxIndex = 0;
- syntaxIndex < EDIS_MAX_SYNTAXES;
+
+ for (unsigned syntaxIndex = 0;
+ syntaxIndex < EDIS_MAX_SYNTAXES;
++syntaxIndex) {
- CompoundConstantEmitter *operandOrder =
+ CompoundConstantEmitter *operandOrder =
new CompoundConstantEmitter(EDIS_MAX_OPERANDS);
-
+
operandOrderArray->addEntry(operandOrder);
-
+
if (syntaxIndex < numSyntaxes) {
populateOperandOrder(operandOrder, inst, syntaxIndex);
}
}
-
+
infoStruct = NULL;
}
}
@@ -793,25 +840,30 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
operandTypes.addEntry("kOperandTypeARMBranchTarget");
operandTypes.addEntry("kOperandTypeARMSoReg");
operandTypes.addEntry("kOperandTypeARMSoImm");
+ operandTypes.addEntry("kOperandTypeARMRotImm");
operandTypes.addEntry("kOperandTypeARMSoImm2Part");
operandTypes.addEntry("kOperandTypeARMPredicate");
+ operandTypes.addEntry("kOperandTypeAddrModeImm12");
+ operandTypes.addEntry("kOperandTypeLdStSOReg");
operandTypes.addEntry("kOperandTypeARMAddrMode2");
operandTypes.addEntry("kOperandTypeARMAddrMode2Offset");
operandTypes.addEntry("kOperandTypeARMAddrMode3");
operandTypes.addEntry("kOperandTypeARMAddrMode3Offset");
- operandTypes.addEntry("kOperandTypeARMAddrMode4");
+ operandTypes.addEntry("kOperandTypeARMLdStmMode");
operandTypes.addEntry("kOperandTypeARMAddrMode5");
operandTypes.addEntry("kOperandTypeARMAddrMode6");
operandTypes.addEntry("kOperandTypeARMAddrMode6Offset");
operandTypes.addEntry("kOperandTypeARMAddrModePC");
operandTypes.addEntry("kOperandTypeARMRegisterList");
+ operandTypes.addEntry("kOperandTypeARMDPRRegisterList");
+ operandTypes.addEntry("kOperandTypeARMSPRRegisterList");
operandTypes.addEntry("kOperandTypeARMTBAddrMode");
operandTypes.addEntry("kOperandTypeThumbITMask");
- operandTypes.addEntry("kOperandTypeThumbAddrModeS1");
- operandTypes.addEntry("kOperandTypeThumbAddrModeS2");
- operandTypes.addEntry("kOperandTypeThumbAddrModeS4");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeRegS");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeImmS");
operandTypes.addEntry("kOperandTypeThumbAddrModeRR");
operandTypes.addEntry("kOperandTypeThumbAddrModeSP");
+ operandTypes.addEntry("kOperandTypeThumbAddrModePC");
operandTypes.addEntry("kOperandTypeThumb2SoReg");
operandTypes.addEntry("kOperandTypeThumb2SoImm");
operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8");
@@ -821,16 +873,16 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4");
operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4Offset");
operandTypes.emit(o, i);
-
+
o << "\n";
-
+
EnumEmitter operandFlags("OperandFlags");
operandFlags.addEntry("kOperandFlagSource");
operandFlags.addEntry("kOperandFlagTarget");
operandFlags.emitAsFlags(o, i);
-
+
o << "\n";
-
+
EnumEmitter instructionTypes("InstructionTypes");
instructionTypes.addEntry("kInstructionTypeNone");
instructionTypes.addEntry("kInstructionTypeMove");
@@ -840,25 +892,25 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
instructionTypes.addEntry("kInstructionTypeCall");
instructionTypes.addEntry("kInstructionTypeReturn");
instructionTypes.emit(o, i);
-
+
o << "\n";
}
void EDEmitter::run(raw_ostream &o) {
unsigned int i = 0;
-
+
CompoundConstantEmitter infoArray;
- CodeGenTarget target;
-
+ CodeGenTarget target(Records);
+
populateInstInfo(infoArray, target);
-
+
emitCommonEnums(o, i);
-
+
o << "namespace {\n";
-
+
o << "llvm::EDInstInfo instInfo" << target.getName().c_str() << "[] = ";
infoArray.emit(o, i);
o << ";" << "\n";
-
+
o << "}\n";
}
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index 6c16fcfaa8a2..f01de1dcfce6 100644
--- a/utils/TableGen/FastISelEmitter.cpp
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -20,6 +20,7 @@
#include "FastISelEmitter.h"
#include "Record.h"
#include "llvm/Support/Debug.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/VectorExtras.h"
using namespace llvm;
@@ -65,23 +66,23 @@ struct OperandsSignature {
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.
// For now, filter out any operand with multiple values.
if (!Op->getPredicateFns().empty() ||
Op->getNumTypes() != 1)
return false;
-
+
assert(Op->hasTypeSet(0) && "Type infererence not done?");
// For now, all the operands must have the same type.
if (Op->getType(0) != VT)
return false;
-
+
if (!Op->isLeaf()) {
if (Op->getOperator()->getName() == "imm") {
Operands.push_back("i");
@@ -107,7 +108,7 @@ struct OperandsSignature {
RC = Target.getRegisterClassForRegister(OpLeafRec);
else
return false;
-
+
// For now, this needs to be a register class of some sort.
if (!RC)
return false;
@@ -212,7 +213,7 @@ class FastISelMap {
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>
+ typedef std::map<OperandsSignature, OpcodeTypeRetPredMap>
OperandsOpcodeTypeRetPredMap;
OperandsOpcodeTypeRetPredMap SimplePatterns;
@@ -263,9 +264,9 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
if (!Op->isSubClassOf("Instruction"))
continue;
CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op);
- if (II.OperandList.empty())
+ if (II.Operands.size() == 0)
continue;
-
+
// For now, ignore multi-instruction patterns.
bool MultiInsts = false;
for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) {
@@ -285,7 +286,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
const CodeGenRegisterClass *DstRC = 0;
std::string SubRegNo;
if (Op->getName() != "EXTRACT_SUBREG") {
- Record *Op0Rec = II.OperandList[0].Rec;
+ Record *Op0Rec = II.Operands[0].Rec;
if (!Op0Rec->isSubClassOf("RegisterClass"))
continue;
DstRC = &Target.getRegisterClass(Op0Rec);
@@ -295,7 +296,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
// If this isn't a leaf, then continue since the register classes are
// a bit too complicated for now.
if (!Dst->getChild(1)->isLeaf()) continue;
-
+
DefInit *SR = dynamic_cast<DefInit*>(Dst->getChild(1)->getLeafValue());
if (SR)
SubRegNo = getQualifiedName(SR->getDef());
@@ -310,7 +311,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
// Ignore multiple result nodes for now.
if (InstPatNode->getNumTypes() > 1) continue;
-
+
Record *InstPatOp = InstPatNode->getOperator();
std::string OpcodeName = getOpcodeName(InstPatOp, CGP);
MVT::SimpleValueType RetVT = MVT::isVoid;
@@ -334,7 +335,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
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" ||
@@ -347,7 +348,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
PhysRegInputs->push_back("");
continue;
}
-
+
DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue());
Record *OpLeafRec = OpDI->getDef();
std::string PhysReg;
@@ -355,7 +356,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
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) {
@@ -364,7 +365,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
}
}
}
-
+
PhysRegInputs->push_back(PhysReg);
}
} else
@@ -380,9 +381,10 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
SubRegNo,
PhysRegInputs
};
- assert(!SimplePatterns[Operands][OpcodeName][VT][RetVT]
- .count(PredicateCheck) &&
- "Duplicate pattern!");
+ if (SimplePatterns[Operands][OpcodeName][VT][RetVT]
+ .count(PredicateCheck))
+ throw TGError(Pattern.getSrcRecord()->getLoc(), "Duplicate record!");
+
SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo;
}
}
@@ -429,7 +431,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
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 "
@@ -439,14 +441,14 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << " ";
HasPred = true;
}
-
+
for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) {
if ((*Memo.PhysRegs)[i] != "")
OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, "
<< "TII.get(TargetOpcode::COPY), "
<< (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n";
}
-
+
OS << " return FastEmitInst_";
if (Memo.SubRegNo.empty()) {
Operands.PrintManglingSuffix(OS, *Memo.PhysRegs);
@@ -462,10 +464,10 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << Memo.SubRegNo;
OS << ");\n";
}
-
+
if (HasPred)
OS << " }\n";
-
+
}
// Return 0 if none of the predicates were satisfied.
if (HasPred)
@@ -473,7 +475,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << "}\n";
OS << "\n";
}
-
+
// Emit one function for the type that demultiplexes on return type.
OS << "unsigned FastEmit_"
<< getLegalCName(Opcode) << "_"
@@ -496,7 +498,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << ");\n";
}
OS << " default: return 0;\n}\n}\n\n";
-
+
} else {
// Non-variadic return type.
OS << "unsigned FastEmit_"
@@ -508,13 +510,13 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << ", ";
Operands.PrintParameters(OS);
OS << ") {\n";
-
+
OS << " if (RetVT.SimpleTy != " << 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;
@@ -531,16 +533,16 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << " ";
HasPred = true;
}
-
+
for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) {
if ((*Memo.PhysRegs)[i] != "")
OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, "
<< "TII.get(TargetOpcode::COPY), "
<< (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n";
}
-
+
OS << " return FastEmitInst_";
-
+
if (Memo.SubRegNo.empty()) {
Operands.PrintManglingSuffix(OS, *Memo.PhysRegs);
OS << "(" << InstNS << Memo.Name << ", ";
@@ -554,11 +556,11 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) {
OS << Memo.SubRegNo;
OS << ");\n";
}
-
+
if (HasPred)
OS << " }\n";
}
-
+
// Return 0 if none of the predicates were satisfied.
if (HasPred)
OS << " return 0;\n";
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
new file mode 100644
index 000000000000..2c222b39b137
--- /dev/null
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -0,0 +1,1372 @@
+//===------------ FixedLenDecoderEmitter.cpp - Decoder Generator ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// It contains the tablegen backend that emits the decoder functions for
+// targets with fixed length instruction set.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "decoder-emitter"
+
+#include "FixedLenDecoderEmitter.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <vector>
+#include <map>
+#include <string>
+
+using namespace llvm;
+
+// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system
+// for a bit value.
+//
+// BIT_UNFILTERED is used as the init value for a filter position. It is used
+// only for filter processings.
+typedef enum {
+ BIT_TRUE, // '1'
+ BIT_FALSE, // '0'
+ BIT_UNSET, // '?'
+ BIT_UNFILTERED // unfiltered
+} bit_value_t;
+
+static bool ValueSet(bit_value_t V) {
+ return (V == BIT_TRUE || V == BIT_FALSE);
+}
+static bool ValueNotSet(bit_value_t V) {
+ return (V == BIT_UNSET);
+}
+static int Value(bit_value_t V) {
+ return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1);
+}
+static bit_value_t bitFromBits(BitsInit &bits, unsigned index) {
+ if (BitInit *bit = dynamic_cast<BitInit*>(bits.getBit(index)))
+ return bit->getValue() ? BIT_TRUE : BIT_FALSE;
+
+ // The bit is uninitialized.
+ return BIT_UNSET;
+}
+// Prints the bit value for each position.
+static void dumpBits(raw_ostream &o, BitsInit &bits) {
+ unsigned index;
+
+ for (index = bits.getNumBits(); index > 0; index--) {
+ switch (bitFromBits(bits, index - 1)) {
+ case BIT_TRUE:
+ o << "1";
+ break;
+ case BIT_FALSE:
+ o << "0";
+ break;
+ case BIT_UNSET:
+ o << "_";
+ break;
+ default:
+ assert(0 && "unexpected return value from bitFromBits");
+ }
+ }
+}
+
+static BitsInit &getBitsField(const Record &def, const char *str) {
+ BitsInit *bits = def.getValueAsBitsInit(str);
+ return *bits;
+}
+
+// Forward declaration.
+class FilterChooser;
+
+// FIXME: Possibly auto-detected?
+#define BIT_WIDTH 32
+
+// Representation of the instruction to work on.
+typedef bit_value_t insn_t[BIT_WIDTH];
+
+/// Filter - Filter works with FilterChooser to produce the decoding tree for
+/// the ISA.
+///
+/// It is useful to think of a Filter as governing the switch stmts of the
+/// decoding tree in a certain level. Each case stmt delegates to an inferior
+/// FilterChooser to decide what further decoding logic to employ, or in another
+/// words, what other remaining bits to look at. The FilterChooser eventually
+/// chooses a best Filter to do its job.
+///
+/// This recursive scheme ends when the number of Opcodes assigned to the
+/// FilterChooser becomes 1 or if there is a conflict. A conflict happens when
+/// the Filter/FilterChooser combo does not know how to distinguish among the
+/// Opcodes assigned.
+///
+/// An example of a conflict is
+///
+/// Conflict:
+/// 111101000.00........00010000....
+/// 111101000.00........0001........
+/// 1111010...00........0001........
+/// 1111010...00....................
+/// 1111010.........................
+/// 1111............................
+/// ................................
+/// VST4q8a 111101000_00________00010000____
+/// VST4q8b 111101000_00________00010000____
+///
+/// The Debug output shows the path that the decoding tree follows to reach the
+/// the conclusion that there is a conflict. VST4q8a is a vst4 to double-spaced
+/// even registers, while VST4q8b is a vst4 to double-spaced odd regsisters.
+///
+/// The encoding info in the .td files does not specify this meta information,
+/// which could have been used by the decoder to resolve the conflict. The
+/// decoder could try to decode the even/odd register numbering and assign to
+/// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a"
+/// version and return the Opcode since the two have the same Asm format string.
+class Filter {
+protected:
+ FilterChooser *Owner; // points to the FilterChooser who owns this filter
+ unsigned StartBit; // the starting bit position
+ unsigned NumBits; // number of bits to filter
+ bool Mixed; // a mixed region contains both set and unset bits
+
+ // Map of well-known segment value to the set of uid's with that value.
+ std::map<uint64_t, std::vector<unsigned> > FilteredInstructions;
+
+ // Set of uid's with non-constant segment values.
+ std::vector<unsigned> VariableInstructions;
+
+ // Map of well-known segment value to its delegate.
+ std::map<unsigned, FilterChooser*> FilterChooserMap;
+
+ // Number of instructions which fall under FilteredInstructions category.
+ unsigned NumFiltered;
+
+ // Keeps track of the last opcode in the filtered bucket.
+ unsigned LastOpcFiltered;
+
+ // Number of instructions which fall under VariableInstructions category.
+ unsigned NumVariable;
+
+public:
+ unsigned getNumFiltered() { return NumFiltered; }
+ unsigned getNumVariable() { return NumVariable; }
+ unsigned getSingletonOpc() {
+ assert(NumFiltered == 1);
+ return LastOpcFiltered;
+ }
+ // Return the filter chooser for the group of instructions without constant
+ // segment values.
+ FilterChooser &getVariableFC() {
+ assert(NumFiltered == 1);
+ assert(FilterChooserMap.size() == 1);
+ return *(FilterChooserMap.find((unsigned)-1)->second);
+ }
+
+ Filter(const Filter &f);
+ Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, bool mixed);
+
+ ~Filter();
+
+ // Divides the decoding task into sub tasks and delegates them to the
+ // inferior FilterChooser's.
+ //
+ // A special case arises when there's only one entry in the filtered
+ // instructions. In order to unambiguously decode the singleton, we need to
+ // match the remaining undecoded encoding bits against the singleton.
+ void recurse();
+
+ // Emit code to decode instructions given a segment or segments of bits.
+ void emit(raw_ostream &o, unsigned &Indentation);
+
+ // Returns the number of fanout produced by the filter. More fanout implies
+ // the filter distinguishes more categories of instructions.
+ unsigned usefulness() const;
+}; // End of class Filter
+
+// These are states of our finite state machines used in FilterChooser's
+// filterProcessor() which produces the filter candidates to use.
+typedef enum {
+ ATTR_NONE,
+ ATTR_FILTERED,
+ ATTR_ALL_SET,
+ ATTR_ALL_UNSET,
+ ATTR_MIXED
+} bitAttr_t;
+
+/// FilterChooser - FilterChooser chooses the best filter among a set of Filters
+/// in order to perform the decoding of instructions at the current level.
+///
+/// Decoding proceeds from the top down. Based on the well-known encoding bits
+/// of instructions available, FilterChooser builds up the possible Filters that
+/// can further the task of decoding by distinguishing among the remaining
+/// candidate instructions.
+///
+/// Once a filter has been chosen, it is called upon to divide the decoding task
+/// into sub-tasks and delegates them to its inferior FilterChoosers for further
+/// processings.
+///
+/// It is useful to think of a Filter as governing the switch stmts of the
+/// decoding tree. And each case is delegated to an inferior FilterChooser to
+/// decide what further remaining bits to look at.
+class FilterChooser {
+protected:
+ friend class Filter;
+
+ // Vector of codegen instructions to choose our filter.
+ const std::vector<const CodeGenInstruction*> &AllInstructions;
+
+ // Vector of uid's for this filter chooser to work on.
+ const std::vector<unsigned> Opcodes;
+
+ // Lookup table for the operand decoding of instructions.
+ std::map<unsigned, std::vector<OperandInfo> > &Operands;
+
+ // Vector of candidate filters.
+ std::vector<Filter> Filters;
+
+ // Array of bit values passed down from our parent.
+ // Set to all BIT_UNFILTERED's for Parent == NULL.
+ bit_value_t FilterBitValues[BIT_WIDTH];
+
+ // Links to the FilterChooser above us in the decoding tree.
+ FilterChooser *Parent;
+
+ // Index of the best filter from Filters.
+ int BestIndex;
+
+public:
+ FilterChooser(const FilterChooser &FC) :
+ AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes),
+ Operands(FC.Operands), Filters(FC.Filters), Parent(FC.Parent),
+ BestIndex(FC.BestIndex) {
+ memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues));
+ }
+
+ FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ const std::vector<unsigned> &IDs,
+ std::map<unsigned, std::vector<OperandInfo> > &Ops) :
+ AllInstructions(Insts), Opcodes(IDs), Operands(Ops), Filters(),
+ Parent(NULL), BestIndex(-1) {
+ for (unsigned i = 0; i < BIT_WIDTH; ++i)
+ FilterBitValues[i] = BIT_UNFILTERED;
+
+ doFilter();
+ }
+
+ FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ const std::vector<unsigned> &IDs,
+ std::map<unsigned, std::vector<OperandInfo> > &Ops,
+ bit_value_t (&ParentFilterBitValues)[BIT_WIDTH],
+ FilterChooser &parent) :
+ AllInstructions(Insts), Opcodes(IDs), Operands(Ops),
+ Filters(), Parent(&parent), BestIndex(-1) {
+ for (unsigned i = 0; i < BIT_WIDTH; ++i)
+ FilterBitValues[i] = ParentFilterBitValues[i];
+
+ doFilter();
+ }
+
+ // The top level filter chooser has NULL as its parent.
+ bool isTopLevel() { return Parent == NULL; }
+
+ // Emit the top level typedef and decodeInstruction() function.
+ void emitTop(raw_ostream &o, unsigned Indentation);
+
+protected:
+ // Populates the insn given the uid.
+ void insnWithID(insn_t &Insn, unsigned Opcode) const {
+ BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst");
+
+ for (unsigned i = 0; i < BIT_WIDTH; ++i)
+ Insn[i] = bitFromBits(Bits, i);
+ }
+
+ // Returns the record name.
+ const std::string &nameWithID(unsigned Opcode) const {
+ return AllInstructions[Opcode]->TheDef->getName();
+ }
+
+ // Populates the field of the insn given the start position and the number of
+ // consecutive bits to scan for.
+ //
+ // Returns false if there exists any uninitialized bit value in the range.
+ // Returns true, otherwise.
+ bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit,
+ unsigned NumBits) const;
+
+ /// dumpFilterArray - dumpFilterArray prints out debugging info for the given
+ /// filter array as a series of chars.
+ void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[BIT_WIDTH]);
+
+ /// dumpStack - dumpStack traverses the filter chooser chain and calls
+ /// dumpFilterArray on each filter chooser up to the top level one.
+ void dumpStack(raw_ostream &o, const char *prefix);
+
+ Filter &bestFilter() {
+ assert(BestIndex != -1 && "BestIndex not set");
+ return Filters[BestIndex];
+ }
+
+ // Called from Filter::recurse() when singleton exists. For debug purpose.
+ void SingletonExists(unsigned Opc);
+
+ bool PositionFiltered(unsigned i) {
+ return ValueSet(FilterBitValues[i]);
+ }
+
+ // Calculates the island(s) needed to decode the instruction.
+ // This returns a lit of undecoded bits of an instructions, for example,
+ // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be
+ // decoded bits in order to verify that the instruction matches the Opcode.
+ unsigned getIslands(std::vector<unsigned> &StartBits,
+ std::vector<unsigned> &EndBits, std::vector<uint64_t> &FieldVals,
+ insn_t &Insn);
+
+ // Emits code to decode the singleton. Return true if we have matched all the
+ // well-known bits.
+ bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,unsigned Opc);
+
+ // Emits code to decode the singleton, and then to decode the rest.
+ void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,Filter &Best);
+
+ // Assign a single filter and run with it.
+ void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit,
+ bool mixed);
+
+ // reportRegion is a helper function for filterProcessor to mark a region as
+ // eligible for use as a filter region.
+ void reportRegion(bitAttr_t RA, unsigned StartBit, unsigned BitIndex,
+ bool AllowMixed);
+
+ // FilterProcessor scans the well-known encoding bits of the instructions and
+ // builds up a list of candidate filters. It chooses the best filter and
+ // recursively descends down the decoding tree.
+ bool filterProcessor(bool AllowMixed, bool Greedy = true);
+
+ // Decides on the best configuration of filter(s) to use in order to decode
+ // the instructions. A conflict of instructions may occur, in which case we
+ // dump the conflict set to the standard error.
+ void doFilter();
+
+ // Emits code to decode our share of instructions. Returns true if the
+ // emitted code causes a return, which occurs if we know how to decode
+ // the instruction at this level or the instruction is not decodeable.
+ bool emit(raw_ostream &o, unsigned &Indentation);
+};
+
+///////////////////////////
+// //
+// Filter Implmenetation //
+// //
+///////////////////////////
+
+Filter::Filter(const Filter &f) :
+ Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed),
+ FilteredInstructions(f.FilteredInstructions),
+ VariableInstructions(f.VariableInstructions),
+ FilterChooserMap(f.FilterChooserMap), NumFiltered(f.NumFiltered),
+ LastOpcFiltered(f.LastOpcFiltered), NumVariable(f.NumVariable) {
+}
+
+Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
+ bool mixed) : Owner(&owner), StartBit(startBit), NumBits(numBits),
+ Mixed(mixed) {
+ assert(StartBit + NumBits - 1 < BIT_WIDTH);
+
+ NumFiltered = 0;
+ LastOpcFiltered = 0;
+ NumVariable = 0;
+
+ for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) {
+ insn_t Insn;
+
+ // Populates the insn given the uid.
+ Owner->insnWithID(Insn, Owner->Opcodes[i]);
+
+ uint64_t Field;
+ // Scans the segment for possibly well-specified encoding bits.
+ bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits);
+
+ if (ok) {
+ // The encoding bits are well-known. Lets add the uid of the
+ // instruction into the bucket keyed off the constant field value.
+ LastOpcFiltered = Owner->Opcodes[i];
+ FilteredInstructions[Field].push_back(LastOpcFiltered);
+ ++NumFiltered;
+ } else {
+ // Some of the encoding bit(s) are unspecfied. This contributes to
+ // one additional member of "Variable" instructions.
+ VariableInstructions.push_back(Owner->Opcodes[i]);
+ ++NumVariable;
+ }
+ }
+
+ assert((FilteredInstructions.size() + VariableInstructions.size() > 0)
+ && "Filter returns no instruction categories");
+}
+
+Filter::~Filter() {
+ std::map<unsigned, FilterChooser*>::iterator filterIterator;
+ for (filterIterator = FilterChooserMap.begin();
+ filterIterator != FilterChooserMap.end();
+ filterIterator++) {
+ delete filterIterator->second;
+ }
+}
+
+// Divides the decoding task into sub tasks and delegates them to the
+// inferior FilterChooser's.
+//
+// A special case arises when there's only one entry in the filtered
+// instructions. In order to unambiguously decode the singleton, we need to
+// match the remaining undecoded encoding bits against the singleton.
+void Filter::recurse() {
+ std::map<uint64_t, std::vector<unsigned> >::const_iterator mapIterator;
+
+ bit_value_t BitValueArray[BIT_WIDTH];
+ // Starts by inheriting our parent filter chooser's filter bit values.
+ memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray));
+
+ unsigned bitIndex;
+
+ if (VariableInstructions.size()) {
+ // Conservatively marks each segment position as BIT_UNSET.
+ for (bitIndex = 0; bitIndex < NumBits; bitIndex++)
+ BitValueArray[StartBit + bitIndex] = BIT_UNSET;
+
+ // Delegates to an inferior filter chooser for futher processing on this
+ // group of instructions whose segment values are variable.
+ FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ (unsigned)-1,
+ new FilterChooser(Owner->AllInstructions,
+ VariableInstructions,
+ Owner->Operands,
+ BitValueArray,
+ *Owner)
+ ));
+ }
+
+ // No need to recurse for a singleton filtered instruction.
+ // See also Filter::emit().
+ if (getNumFiltered() == 1) {
+ //Owner->SingletonExists(LastOpcFiltered);
+ assert(FilterChooserMap.size() == 1);
+ return;
+ }
+
+ // Otherwise, create sub choosers.
+ for (mapIterator = FilteredInstructions.begin();
+ mapIterator != FilteredInstructions.end();
+ mapIterator++) {
+
+ // Marks all the segment positions with either BIT_TRUE or BIT_FALSE.
+ for (bitIndex = 0; bitIndex < NumBits; bitIndex++) {
+ if (mapIterator->first & (1ULL << bitIndex))
+ BitValueArray[StartBit + bitIndex] = BIT_TRUE;
+ else
+ BitValueArray[StartBit + bitIndex] = BIT_FALSE;
+ }
+
+ // Delegates to an inferior filter chooser for futher processing on this
+ // category of instructions.
+ FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ mapIterator->first,
+ new FilterChooser(Owner->AllInstructions,
+ mapIterator->second,
+ Owner->Operands,
+ BitValueArray,
+ *Owner)
+ ));
+ }
+}
+
+// Emit code to decode instructions given a segment or segments of bits.
+void Filter::emit(raw_ostream &o, unsigned &Indentation) {
+ o.indent(Indentation) << "// Check Inst{";
+
+ if (NumBits > 1)
+ o << (StartBit + NumBits - 1) << '-';
+
+ o << StartBit << "} ...\n";
+
+ o.indent(Indentation) << "switch (fieldFromInstruction(insn, "
+ << StartBit << ", " << NumBits << ")) {\n";
+
+ std::map<unsigned, FilterChooser*>::iterator filterIterator;
+
+ bool DefaultCase = false;
+ for (filterIterator = FilterChooserMap.begin();
+ filterIterator != FilterChooserMap.end();
+ filterIterator++) {
+
+ // Field value -1 implies a non-empty set of variable instructions.
+ // See also recurse().
+ if (filterIterator->first == (unsigned)-1) {
+ DefaultCase = true;
+
+ o.indent(Indentation) << "default:\n";
+ o.indent(Indentation) << " break; // fallthrough\n";
+
+ // Closing curly brace for the switch statement.
+ // This is unconventional because we want the default processing to be
+ // performed for the fallthrough cases as well, i.e., when the "cases"
+ // did not prove a decoded instruction.
+ o.indent(Indentation) << "}\n";
+
+ } else
+ o.indent(Indentation) << "case " << filterIterator->first << ":\n";
+
+ // We arrive at a category of instructions with the same segment value.
+ // Now delegate to the sub filter chooser for further decodings.
+ // The case may fallthrough, which happens if the remaining well-known
+ // encoding bits do not match exactly.
+ if (!DefaultCase) { ++Indentation; ++Indentation; }
+
+ bool finished = filterIterator->second->emit(o, Indentation);
+ // For top level default case, there's no need for a break statement.
+ if (Owner->isTopLevel() && DefaultCase)
+ break;
+ if (!finished)
+ o.indent(Indentation) << "break;\n";
+
+ if (!DefaultCase) { --Indentation; --Indentation; }
+ }
+
+ // If there is no default case, we still need to supply a closing brace.
+ if (!DefaultCase) {
+ // Closing curly brace for the switch statement.
+ o.indent(Indentation) << "}\n";
+ }
+}
+
+// Returns the number of fanout produced by the filter. More fanout implies
+// the filter distinguishes more categories of instructions.
+unsigned Filter::usefulness() const {
+ if (VariableInstructions.size())
+ return FilteredInstructions.size();
+ else
+ return FilteredInstructions.size() + 1;
+}
+
+//////////////////////////////////
+// //
+// Filterchooser Implementation //
+// //
+//////////////////////////////////
+
+// Emit the top level typedef and decodeInstruction() function.
+void FilterChooser::emitTop(raw_ostream &o, unsigned Indentation) {
+ switch (BIT_WIDTH) {
+ case 8:
+ o.indent(Indentation) << "typedef uint8_t field_t;\n";
+ break;
+ case 16:
+ o.indent(Indentation) << "typedef uint16_t field_t;\n";
+ break;
+ case 32:
+ o.indent(Indentation) << "typedef uint32_t field_t;\n";
+ break;
+ case 64:
+ o.indent(Indentation) << "typedef uint64_t field_t;\n";
+ break;
+ default:
+ assert(0 && "Unexpected instruction size!");
+ }
+
+ o << '\n';
+
+ o.indent(Indentation) << "static field_t " <<
+ "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n";
+
+ o.indent(Indentation) << "{\n";
+
+ ++Indentation; ++Indentation;
+ o.indent(Indentation) << "assert(startBit + numBits <= " << BIT_WIDTH
+ << " && \"Instruction field out of bounds!\");\n";
+ o << '\n';
+ o.indent(Indentation) << "field_t fieldMask;\n";
+ o << '\n';
+ o.indent(Indentation) << "if (numBits == " << BIT_WIDTH << ")\n";
+
+ ++Indentation; ++Indentation;
+ o.indent(Indentation) << "fieldMask = (field_t)-1;\n";
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "else\n";
+
+ ++Indentation; ++Indentation;
+ o.indent(Indentation) << "fieldMask = ((1 << numBits) - 1) << startBit;\n";
+ --Indentation; --Indentation;
+
+ o << '\n';
+ o.indent(Indentation) << "return (insn & fieldMask) >> startBit;\n";
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "}\n";
+
+ o << '\n';
+
+ o.indent(Indentation) <<
+ "static bool decodeInstruction(MCInst &MI, field_t insn) {\n";
+ o.indent(Indentation) << " unsigned tmp = 0;\n";
+
+ ++Indentation; ++Indentation;
+ // Emits code to decode the instructions.
+ emit(o, Indentation);
+
+ o << '\n';
+ o.indent(Indentation) << "return false;\n";
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "}\n";
+
+ o << '\n';
+}
+
+// Populates the field of the insn given the start position and the number of
+// consecutive bits to scan for.
+//
+// Returns false if and on the first uninitialized bit value encountered.
+// Returns true, otherwise.
+bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
+ unsigned StartBit, unsigned NumBits) const {
+ Field = 0;
+
+ for (unsigned i = 0; i < NumBits; ++i) {
+ if (Insn[StartBit + i] == BIT_UNSET)
+ return false;
+
+ if (Insn[StartBit + i] == BIT_TRUE)
+ Field = Field | (1ULL << i);
+ }
+
+ return true;
+}
+
+/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
+/// filter array as a series of chars.
+void FilterChooser::dumpFilterArray(raw_ostream &o,
+ bit_value_t (&filter)[BIT_WIDTH]) {
+ unsigned bitIndex;
+
+ for (bitIndex = BIT_WIDTH; bitIndex > 0; bitIndex--) {
+ switch (filter[bitIndex - 1]) {
+ case BIT_UNFILTERED:
+ o << ".";
+ break;
+ case BIT_UNSET:
+ o << "_";
+ break;
+ case BIT_TRUE:
+ o << "1";
+ break;
+ case BIT_FALSE:
+ o << "0";
+ break;
+ }
+ }
+}
+
+/// dumpStack - dumpStack traverses the filter chooser chain and calls
+/// dumpFilterArray on each filter chooser up to the top level one.
+void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
+ FilterChooser *current = this;
+
+ while (current) {
+ o << prefix;
+ dumpFilterArray(o, current->FilterBitValues);
+ o << '\n';
+ current = current->Parent;
+ }
+}
+
+// Called from Filter::recurse() when singleton exists. For debug purpose.
+void FilterChooser::SingletonExists(unsigned Opc) {
+ insn_t Insn0;
+ insnWithID(Insn0, Opc);
+
+ errs() << "Singleton exists: " << nameWithID(Opc)
+ << " with its decoding dominating ";
+ for (unsigned i = 0; i < Opcodes.size(); ++i) {
+ if (Opcodes[i] == Opc) continue;
+ errs() << nameWithID(Opcodes[i]) << ' ';
+ }
+ errs() << '\n';
+
+ dumpStack(errs(), "\t\t");
+ for (unsigned i = 0; i < Opcodes.size(); i++) {
+ const std::string &Name = nameWithID(Opcodes[i]);
+
+ errs() << '\t' << Name << " ";
+ dumpBits(errs(),
+ getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
+ errs() << '\n';
+ }
+}
+
+// Calculates the island(s) needed to decode the instruction.
+// This returns a list of undecoded bits of an instructions, for example,
+// Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be
+// decoded bits in order to verify that the instruction matches the Opcode.
+unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
+ std::vector<unsigned> &EndBits, std::vector<uint64_t> &FieldVals,
+ insn_t &Insn) {
+ unsigned Num, BitNo;
+ Num = BitNo = 0;
+
+ uint64_t FieldVal = 0;
+
+ // 0: Init
+ // 1: Water (the bit value does not affect decoding)
+ // 2: Island (well-known bit value needed for decoding)
+ int State = 0;
+ int Val = -1;
+
+ for (unsigned i = 0; i < BIT_WIDTH; ++i) {
+ Val = Value(Insn[i]);
+ bool Filtered = PositionFiltered(i);
+ switch (State) {
+ default:
+ assert(0 && "Unreachable code!");
+ break;
+ case 0:
+ case 1:
+ if (Filtered || Val == -1)
+ State = 1; // Still in Water
+ else {
+ State = 2; // Into the Island
+ BitNo = 0;
+ StartBits.push_back(i);
+ FieldVal = Val;
+ }
+ break;
+ case 2:
+ if (Filtered || Val == -1) {
+ State = 1; // Into the Water
+ EndBits.push_back(i - 1);
+ FieldVals.push_back(FieldVal);
+ ++Num;
+ } else {
+ State = 2; // Still in Island
+ ++BitNo;
+ FieldVal = FieldVal | Val << BitNo;
+ }
+ break;
+ }
+ }
+ // If we are still in Island after the loop, do some housekeeping.
+ if (State == 2) {
+ EndBits.push_back(BIT_WIDTH - 1);
+ FieldVals.push_back(FieldVal);
+ ++Num;
+ }
+
+ assert(StartBits.size() == Num && EndBits.size() == Num &&
+ FieldVals.size() == Num);
+ return Num;
+}
+
+// Emits code to decode the singleton. Return true if we have matched all the
+// well-known bits.
+bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ unsigned Opc) {
+ std::vector<unsigned> StartBits;
+ std::vector<unsigned> EndBits;
+ std::vector<uint64_t> FieldVals;
+ insn_t Insn;
+ insnWithID(Insn, Opc);
+
+ // Look for islands of undecoded bits of the singleton.
+ getIslands(StartBits, EndBits, FieldVals, Insn);
+
+ unsigned Size = StartBits.size();
+ unsigned I, NumBits;
+
+ // If we have matched all the well-known bits, just issue a return.
+ if (Size == 0) {
+ o.indent(Indentation) << "{\n";
+ o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n";
+ std::vector<OperandInfo>& InsnOperands = Operands[Opc];
+ for (std::vector<OperandInfo>::iterator
+ I = InsnOperands.begin(), E = InsnOperands.end(); I != E; ++I) {
+ // If a custom instruction decoder was specified, use that.
+ if (I->FieldBase == ~0U && I->FieldLength == ~0U) {
+ o.indent(Indentation) << " " << I->Decoder << "(MI, insn);\n";
+ break;
+ }
+
+ o.indent(Indentation)
+ << " tmp = fieldFromInstruction(insn, " << I->FieldBase
+ << ", " << I->FieldLength << ");\n";
+ if (I->Decoder != "") {
+ o.indent(Indentation) << " " << I->Decoder << "(MI, tmp);\n";
+ } else {
+ o.indent(Indentation)
+ << " MI.addOperand(MCOperand::CreateImm(tmp));\n";
+ }
+ }
+
+ o.indent(Indentation) << " return true; // " << nameWithID(Opc)
+ << '\n';
+ o.indent(Indentation) << "}\n";
+ return true;
+ }
+
+ // Otherwise, there are more decodings to be done!
+
+ // Emit code to match the island(s) for the singleton.
+ o.indent(Indentation) << "// Check ";
+
+ for (I = Size; I != 0; --I) {
+ o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} ";
+ if (I > 1)
+ o << "&& ";
+ else
+ o << "for singleton decoding...\n";
+ }
+
+ o.indent(Indentation) << "if (";
+
+ for (I = Size; I != 0; --I) {
+ NumBits = EndBits[I-1] - StartBits[I-1] + 1;
+ o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits
+ << ") == " << FieldVals[I-1];
+ if (I > 1)
+ o << " && ";
+ else
+ o << ") {\n";
+ }
+ o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n";
+ std::vector<OperandInfo>& InsnOperands = Operands[Opc];
+ for (std::vector<OperandInfo>::iterator
+ I = InsnOperands.begin(), E = InsnOperands.end(); I != E; ++I) {
+ // If a custom instruction decoder was specified, use that.
+ if (I->FieldBase == ~0U && I->FieldLength == ~0U) {
+ o.indent(Indentation) << " " << I->Decoder << "(MI, insn);\n";
+ break;
+ }
+
+ o.indent(Indentation)
+ << " tmp = fieldFromInstruction(insn, " << I->FieldBase
+ << ", " << I->FieldLength << ");\n";
+ if (I->Decoder != "") {
+ o.indent(Indentation) << " " << I->Decoder << "(MI, tmp);\n";
+ } else {
+ o.indent(Indentation)
+ << " MI.addOperand(MCOperand::CreateImm(tmp));\n";
+ }
+ }
+ o.indent(Indentation) << " return true; // " << nameWithID(Opc)
+ << '\n';
+ o.indent(Indentation) << "}\n";
+
+ return false;
+}
+
+// Emits code to decode the singleton, and then to decode the rest.
+void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ Filter &Best) {
+
+ unsigned Opc = Best.getSingletonOpc();
+
+ emitSingletonDecoder(o, Indentation, Opc);
+
+ // Emit code for the rest.
+ o.indent(Indentation) << "else\n";
+
+ Indentation += 2;
+ Best.getVariableFC().emit(o, Indentation);
+ Indentation -= 2;
+}
+
+// Assign a single filter and run with it. Top level API client can initialize
+// with a single filter to start the filtering process.
+void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit,
+ unsigned numBit, bool mixed) {
+ Filters.clear();
+ Filter F(*this, startBit, numBit, true);
+ Filters.push_back(F);
+ BestIndex = 0; // Sole Filter instance to choose from.
+ bestFilter().recurse();
+}
+
+// reportRegion is a helper function for filterProcessor to mark a region as
+// eligible for use as a filter region.
+void FilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit,
+ unsigned BitIndex, bool AllowMixed) {
+ if (RA == ATTR_MIXED && AllowMixed)
+ Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, true));
+ else if (RA == ATTR_ALL_SET && !AllowMixed)
+ Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, false));
+}
+
+// FilterProcessor scans the well-known encoding bits of the instructions and
+// builds up a list of candidate filters. It chooses the best filter and
+// recursively descends down the decoding tree.
+bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
+ Filters.clear();
+ BestIndex = -1;
+ unsigned numInstructions = Opcodes.size();
+
+ assert(numInstructions && "Filter created with no instructions");
+
+ // No further filtering is necessary.
+ if (numInstructions == 1)
+ return true;
+
+ // Heuristics. See also doFilter()'s "Heuristics" comment when num of
+ // instructions is 3.
+ if (AllowMixed && !Greedy) {
+ assert(numInstructions == 3);
+
+ for (unsigned i = 0; i < Opcodes.size(); ++i) {
+ std::vector<unsigned> StartBits;
+ std::vector<unsigned> EndBits;
+ std::vector<uint64_t> FieldVals;
+ insn_t Insn;
+
+ insnWithID(Insn, Opcodes[i]);
+
+ // Look for islands of undecoded bits of any instruction.
+ if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) {
+ // Found an instruction with island(s). Now just assign a filter.
+ runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1,
+ true);
+ return true;
+ }
+ }
+ }
+
+ unsigned BitIndex, InsnIndex;
+
+ // We maintain BIT_WIDTH copies of the bitAttrs automaton.
+ // The automaton consumes the corresponding bit from each
+ // instruction.
+ //
+ // Input symbols: 0, 1, and _ (unset).
+ // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED.
+ // Initial state: NONE.
+ //
+ // (NONE) ------- [01] -> (ALL_SET)
+ // (NONE) ------- _ ----> (ALL_UNSET)
+ // (ALL_SET) ---- [01] -> (ALL_SET)
+ // (ALL_SET) ---- _ ----> (MIXED)
+ // (ALL_UNSET) -- [01] -> (MIXED)
+ // (ALL_UNSET) -- _ ----> (ALL_UNSET)
+ // (MIXED) ------ . ----> (MIXED)
+ // (FILTERED)---- . ----> (FILTERED)
+
+ bitAttr_t bitAttrs[BIT_WIDTH];
+
+ // FILTERED bit positions provide no entropy and are not worthy of pursuing.
+ // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position.
+ for (BitIndex = 0; BitIndex < BIT_WIDTH; ++BitIndex)
+ if (FilterBitValues[BitIndex] == BIT_TRUE ||
+ FilterBitValues[BitIndex] == BIT_FALSE)
+ bitAttrs[BitIndex] = ATTR_FILTERED;
+ else
+ bitAttrs[BitIndex] = ATTR_NONE;
+
+ for (InsnIndex = 0; InsnIndex < numInstructions; ++InsnIndex) {
+ insn_t insn;
+
+ insnWithID(insn, Opcodes[InsnIndex]);
+
+ for (BitIndex = 0; BitIndex < BIT_WIDTH; ++BitIndex) {
+ switch (bitAttrs[BitIndex]) {
+ case ATTR_NONE:
+ if (insn[BitIndex] == BIT_UNSET)
+ bitAttrs[BitIndex] = ATTR_ALL_UNSET;
+ else
+ bitAttrs[BitIndex] = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_SET:
+ if (insn[BitIndex] == BIT_UNSET)
+ bitAttrs[BitIndex] = ATTR_MIXED;
+ break;
+ case ATTR_ALL_UNSET:
+ if (insn[BitIndex] != BIT_UNSET)
+ bitAttrs[BitIndex] = ATTR_MIXED;
+ break;
+ case ATTR_MIXED:
+ case ATTR_FILTERED:
+ break;
+ }
+ }
+ }
+
+ // The regionAttr automaton consumes the bitAttrs automatons' state,
+ // lowest-to-highest.
+ //
+ // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed)
+ // States: NONE, ALL_SET, MIXED
+ // Initial state: NONE
+ //
+ // (NONE) ----- F --> (NONE)
+ // (NONE) ----- S --> (ALL_SET) ; and set region start
+ // (NONE) ----- U --> (NONE)
+ // (NONE) ----- M --> (MIXED) ; and set region start
+ // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region
+ // (ALL_SET) -- S --> (ALL_SET)
+ // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region
+ // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region
+ // (MIXED) ---- F --> (NONE) ; and report a MIXED region
+ // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region
+ // (MIXED) ---- U --> (NONE) ; and report a MIXED region
+ // (MIXED) ---- M --> (MIXED)
+
+ bitAttr_t RA = ATTR_NONE;
+ unsigned StartBit = 0;
+
+ for (BitIndex = 0; BitIndex < BIT_WIDTH; BitIndex++) {
+ bitAttr_t bitAttr = bitAttrs[BitIndex];
+
+ assert(bitAttr != ATTR_NONE && "Bit without attributes");
+
+ switch (RA) {
+ case ATTR_NONE:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ break;
+ case ATTR_ALL_SET:
+ StartBit = BitIndex;
+ RA = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_UNSET:
+ break;
+ case ATTR_MIXED:
+ StartBit = BitIndex;
+ RA = ATTR_MIXED;
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_ALL_SET:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ RA = ATTR_NONE;
+ break;
+ case ATTR_ALL_SET:
+ break;
+ case ATTR_ALL_UNSET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ RA = ATTR_NONE;
+ break;
+ case ATTR_MIXED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ StartBit = BitIndex;
+ RA = ATTR_MIXED;
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_MIXED:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ StartBit = BitIndex;
+ RA = ATTR_NONE;
+ break;
+ case ATTR_ALL_SET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ StartBit = BitIndex;
+ RA = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_UNSET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ RA = ATTR_NONE;
+ break;
+ case ATTR_MIXED:
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_ALL_UNSET:
+ assert(0 && "regionAttr state machine has no ATTR_UNSET state");
+ case ATTR_FILTERED:
+ assert(0 && "regionAttr state machine has no ATTR_FILTERED state");
+ }
+ }
+
+ // At the end, if we're still in ALL_SET or MIXED states, report a region
+ switch (RA) {
+ case ATTR_NONE:
+ break;
+ case ATTR_FILTERED:
+ break;
+ case ATTR_ALL_SET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ break;
+ case ATTR_ALL_UNSET:
+ break;
+ case ATTR_MIXED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ break;
+ }
+
+ // We have finished with the filter processings. Now it's time to choose
+ // the best performing filter.
+ BestIndex = 0;
+ bool AllUseless = true;
+ unsigned BestScore = 0;
+
+ for (unsigned i = 0, e = Filters.size(); i != e; ++i) {
+ unsigned Usefulness = Filters[i].usefulness();
+
+ if (Usefulness)
+ AllUseless = false;
+
+ if (Usefulness > BestScore) {
+ BestIndex = i;
+ BestScore = Usefulness;
+ }
+ }
+
+ if (!AllUseless)
+ bestFilter().recurse();
+
+ return !AllUseless;
+} // end of FilterChooser::filterProcessor(bool)
+
+// Decides on the best configuration of filter(s) to use in order to decode
+// the instructions. A conflict of instructions may occur, in which case we
+// dump the conflict set to the standard error.
+void FilterChooser::doFilter() {
+ unsigned Num = Opcodes.size();
+ assert(Num && "FilterChooser created with no instructions");
+
+ // Try regions of consecutive known bit values first.
+ if (filterProcessor(false))
+ return;
+
+ // Then regions of mixed bits (both known and unitialized bit values allowed).
+ if (filterProcessor(true))
+ return;
+
+ // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where
+ // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a
+ // well-known encoding pattern. In such case, we backtrack and scan for the
+ // the very first consecutive ATTR_ALL_SET region and assign a filter to it.
+ if (Num == 3 && filterProcessor(true, false))
+ return;
+
+ // If we come to here, the instruction decoding has failed.
+ // Set the BestIndex to -1 to indicate so.
+ BestIndex = -1;
+}
+
+// Emits code to decode our share of instructions. Returns true if the
+// emitted code causes a return, which occurs if we know how to decode
+// the instruction at this level or the instruction is not decodeable.
+bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
+ if (Opcodes.size() == 1)
+ // There is only one instruction in the set, which is great!
+ // Call emitSingletonDecoder() to see whether there are any remaining
+ // encodings bits.
+ return emitSingletonDecoder(o, Indentation, Opcodes[0]);
+
+ // Choose the best filter to do the decodings!
+ if (BestIndex != -1) {
+ Filter &Best = bestFilter();
+ if (Best.getNumFiltered() == 1)
+ emitSingletonDecoder(o, Indentation, Best);
+ else
+ bestFilter().emit(o, Indentation);
+ return false;
+ }
+
+ // We don't know how to decode these instructions! Return 0 and dump the
+ // conflict set!
+ o.indent(Indentation) << "return 0;" << " // Conflict set: ";
+ for (int i = 0, N = Opcodes.size(); i < N; ++i) {
+ o << nameWithID(Opcodes[i]);
+ if (i < (N - 1))
+ o << ", ";
+ else
+ o << '\n';
+ }
+
+ // Print out useful conflict information for postmortem analysis.
+ errs() << "Decoding Conflict:\n";
+
+ dumpStack(errs(), "\t\t");
+
+ for (unsigned i = 0; i < Opcodes.size(); i++) {
+ const std::string &Name = nameWithID(Opcodes[i]);
+
+ errs() << '\t' << Name << " ";
+ dumpBits(errs(),
+ getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
+ errs() << '\n';
+ }
+
+ return true;
+}
+
+bool FixedLenDecoderEmitter::populateInstruction(const CodeGenInstruction &CGI,
+ unsigned Opc){
+ const Record &Def = *CGI.TheDef;
+ // If all the bit positions are not specified; do not decode this instruction.
+ // We are bound to fail! For proper disassembly, the well-known encoding bits
+ // of the instruction must be fully specified.
+ //
+ // This also removes pseudo instructions from considerations of disassembly,
+ // which is a better design and less fragile than the name matchings.
+ BitsInit &Bits = getBitsField(Def, "Inst");
+ if (Bits.allInComplete()) return false;
+
+ // Ignore "asm parser only" instructions.
+ if (Def.getValueAsBit("isAsmParserOnly"))
+ return false;
+
+ std::vector<OperandInfo> InsnOperands;
+
+ // If the instruction has specified a custom decoding hook, use that instead
+ // of trying to auto-generate the decoder.
+ std::string InstDecoder = Def.getValueAsString("DecoderMethod");
+ if (InstDecoder != "") {
+ InsnOperands.push_back(OperandInfo(~0U, ~0U, InstDecoder));
+ Operands[Opc] = InsnOperands;
+ return true;
+ }
+
+ // Generate a description of the operand of the instruction that we know
+ // how to decode automatically.
+ // FIXME: We'll need to have a way to manually override this as needed.
+
+ // Gather the outputs/inputs of the instruction, so we can find their
+ // positions in the encoding. This assumes for now that they appear in the
+ // MCInst in the order that they're listed.
+ std::vector<std::pair<Init*, std::string> > InOutOperands;
+ DagInit *Out = Def.getValueAsDag("OutOperandList");
+ DagInit *In = Def.getValueAsDag("InOperandList");
+ for (unsigned i = 0; i < Out->getNumArgs(); ++i)
+ InOutOperands.push_back(std::make_pair(Out->getArg(i), Out->getArgName(i)));
+ for (unsigned i = 0; i < In->getNumArgs(); ++i)
+ InOutOperands.push_back(std::make_pair(In->getArg(i), In->getArgName(i)));
+
+ // For each operand, see if we can figure out where it is encoded.
+ for (std::vector<std::pair<Init*, std::string> >::iterator
+ NI = InOutOperands.begin(), NE = InOutOperands.end(); NI != NE; ++NI) {
+ unsigned PrevBit = ~0;
+ unsigned Base = ~0;
+ unsigned PrevPos = ~0;
+ std::string Decoder = "";
+
+ for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) {
+ VarBitInit *BI = dynamic_cast<VarBitInit*>(Bits.getBit(bi));
+ if (!BI) continue;
+
+ VarInit *Var = dynamic_cast<VarInit*>(BI->getVariable());
+ assert(Var);
+ unsigned CurrBit = BI->getBitNum();
+ if (Var->getName() != NI->second) continue;
+
+ // Figure out the lowest bit of the value, and the width of the field.
+ // Deliberately don't try to handle cases where the field is scattered,
+ // or where not all bits of the the field are explicit.
+ if (Base == ~0U && PrevBit == ~0U && PrevPos == ~0U) {
+ if (CurrBit == 0)
+ Base = bi;
+ else
+ continue;
+ }
+
+ if ((PrevPos != ~0U && bi-1 != PrevPos) ||
+ (CurrBit != ~0U && CurrBit-1 != PrevBit)) {
+ PrevBit = ~0;
+ Base = ~0;
+ PrevPos = ~0;
+ }
+
+ PrevPos = bi;
+ PrevBit = CurrBit;
+
+ // At this point, we can locate the field, but we need to know how to
+ // interpret it. As a first step, require the target to provide callbacks
+ // for decoding register classes.
+ // FIXME: This need to be extended to handle instructions with custom
+ // decoder methods, and operands with (simple) MIOperandInfo's.
+ TypedInit *TI = dynamic_cast<TypedInit*>(NI->first);
+ RecordRecTy *Type = dynamic_cast<RecordRecTy*>(TI->getType());
+ Record *TypeRecord = Type->getRecord();
+ bool isReg = false;
+ if (TypeRecord->isSubClassOf("RegisterClass")) {
+ Decoder = "Decode" + Type->getRecord()->getName() + "RegisterClass";
+ isReg = true;
+ }
+
+ RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod");
+ StringInit *String = DecoderString ?
+ dynamic_cast<StringInit*>(DecoderString->getValue()) :
+ 0;
+ if (!isReg && String && String->getValue() != "")
+ Decoder = String->getValue();
+ }
+
+ if (Base != ~0U) {
+ InsnOperands.push_back(OperandInfo(Base, PrevBit+1, Decoder));
+ DEBUG(errs() << "ENCODED OPERAND: $" << NI->second << " @ ("
+ << utostr(Base+PrevBit) << ", " << utostr(Base) << ")\n");
+ }
+ }
+
+ Operands[Opc] = InsnOperands;
+
+
+#if 0
+ DEBUG({
+ // Dumps the instruction encoding bits.
+ dumpBits(errs(), Bits);
+
+ errs() << '\n';
+
+ // Dumps the list of operand info.
+ for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
+ const CGIOperandList::OperandInfo &Info = CGI.Operands[i];
+ const std::string &OperandName = Info.Name;
+ const Record &OperandDef = *Info.Rec;
+
+ errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n";
+ }
+ });
+#endif
+
+ return true;
+}
+
+void FixedLenDecoderEmitter::populateInstructions() {
+ for (unsigned i = 0, e = NumberedInstructions.size(); i < e; ++i) {
+ Record *R = NumberedInstructions[i]->TheDef;
+ if (R->getValueAsString("Namespace") == "TargetOpcode")
+ continue;
+
+ if (populateInstruction(*NumberedInstructions[i], i))
+ Opcodes.push_back(i);
+ }
+}
+
+// Emits disassembler code for instruction decoding.
+void FixedLenDecoderEmitter::run(raw_ostream &o)
+{
+ o << "#include \"llvm/MC/MCInst.h\"\n";
+ o << "#include \"llvm/Support/DataTypes.h\"\n";
+ o << "#include <assert.h>\n";
+ o << '\n';
+ o << "namespace llvm {\n\n";
+
+ NumberedInstructions = Target.getInstructionsByEnumValue();
+ populateInstructions();
+ FilterChooser FC(NumberedInstructions, Opcodes, Operands);
+ FC.emitTop(o, 0);
+
+ o << "\n} // End llvm namespace \n";
+}
diff --git a/utils/TableGen/FixedLenDecoderEmitter.h b/utils/TableGen/FixedLenDecoderEmitter.h
new file mode 100644
index 000000000000..d46a495540ea
--- /dev/null
+++ b/utils/TableGen/FixedLenDecoderEmitter.h
@@ -0,0 +1,56 @@
+//===------------ FixedLenDecoderEmitter.h - Decoder Generator --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// It contains the tablegen backend that emits the decoder functions for
+// targets with fixed length instruction set.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FixedLenDECODEREMITTER_H
+#define FixedLenDECODEREMITTER_H
+
+#include "CodeGenTarget.h"
+#include "TableGenBackend.h"
+
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+
+struct OperandInfo {
+ unsigned FieldBase;
+ unsigned FieldLength;
+ std::string Decoder;
+
+ OperandInfo(unsigned FB, unsigned FL, std::string D)
+ : FieldBase(FB), FieldLength(FL), Decoder(D) { }
+};
+
+class FixedLenDecoderEmitter : public TableGenBackend {
+public:
+ FixedLenDecoderEmitter(RecordKeeper &R) :
+ Records(R), Target(R),
+ NumberedInstructions(Target.getInstructionsByEnumValue()) {}
+
+ // run - Output the code emitter
+ void run(raw_ostream &o);
+
+private:
+ RecordKeeper &Records;
+ CodeGenTarget Target;
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+ std::vector<unsigned> Opcodes;
+ std::map<unsigned, std::vector<OperandInfo> > Operands;
+
+ bool populateInstruction(const CodeGenInstruction &CGI, unsigned Opc);
+ void populateInstructions();
+};
+
+} // end llvm namespace
+
+#endif
diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp
index 47a8474c35ec..aa596892f52f 100644
--- a/utils/TableGen/InstrEnumEmitter.cpp
+++ b/utils/TableGen/InstrEnumEmitter.cpp
@@ -23,7 +23,7 @@ void InstrEnumEmitter::run(raw_ostream &OS) {
EmitSourceFileHeader("Target Instruction Enum Values", OS);
OS << "namespace llvm {\n\n";
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
// We must emit the PHI opcode first...
std::string Namespace = Target.getInstNamespace();
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index 4d3aa5e621c9..2b684bede3ea 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -60,23 +60,23 @@ 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) {
+ for (unsigned i = 0, e = Inst.Operands.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;
+ std::vector<CGIOperandList::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;
+ DagInit *MIOI = Inst.Operands[i].MIOperandInfo;
if (!MIOI || MIOI->getNumArgs() == 0) {
// Single, anonymous, operand.
- OperandList.push_back(Inst.OperandList[i]);
+ OperandList.push_back(Inst.Operands[i]);
} else {
- for (unsigned j = 0, e = Inst.OperandList[i].MINumOperands; j != e; ++j) {
- OperandList.push_back(Inst.OperandList[i]);
+ for (unsigned j = 0, e = Inst.Operands[i].MINumOperands; j != e; ++j) {
+ OperandList.push_back(Inst.Operands[i]);
Record *OpR = dynamic_cast<DefInit*>(MIOI->getArg(j))->getDef();
OperandList.back().Rec = OpR;
@@ -104,19 +104,19 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
// Predicate operands. Check to see if the original unexpanded operand
// was of type PredicateOperand.
- if (Inst.OperandList[i].Rec->isSubClassOf("PredicateOperand"))
+ if (Inst.Operands[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"))
+ if (Inst.Operands[i].Rec->isSubClassOf("OptionalDefOperand"))
Res += "|(1<<TOI::OptionalDef)";
// Fill in constraint info.
Res += ", ";
- const CodeGenInstruction::ConstraintInfo &Constraint =
- Inst.OperandList[i].Constraints[j];
+ const CGIOperandList::ConstraintInfo &Constraint =
+ Inst.Operands[i].Constraints[j];
if (Constraint.isNone())
Res += "0";
else if (Constraint.isEarlyClobber())
@@ -256,14 +256,14 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS) {
int MinOperands = 0;
- if (!Inst.OperandList.empty())
+ if (!Inst.Operands.size() == 0)
// Each logical operand can be multiple MI operands.
- MinOperands = Inst.OperandList.back().MIOperandNo +
- Inst.OperandList.back().MINumOperands;
+ MinOperands = Inst.Operands.back().MIOperandNo +
+ Inst.Operands.back().MINumOperands;
OS << " { ";
OS << Num << ",\t" << MinOperands << ",\t"
- << Inst.NumDefs << ",\t" << getItinClassNumber(Inst.TheDef)
+ << Inst.Operands.NumDefs << ",\t" << getItinClassNumber(Inst.TheDef)
<< ",\t\"" << Inst.TheDef->getName() << "\", 0";
// Emit all of the target indepedent flags...
@@ -271,6 +271,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
if (Inst.isBranch) OS << "|(1<<TID::Branch)";
if (Inst.isIndirectBranch) OS << "|(1<<TID::IndirectBranch)";
if (Inst.isCompare) OS << "|(1<<TID::Compare)";
+ if (Inst.isMoveImm) OS << "|(1<<TID::MoveImm)";
if (Inst.isBarrier) OS << "|(1<<TID::Barrier)";
if (Inst.hasDelaySlot) OS << "|(1<<TID::DelaySlot)";
if (Inst.isCall) OS << "|(1<<TID::Call)";
@@ -283,9 +284,9 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
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.Operands.hasOptionalDef) OS << "|(1<<TID::HasOptionalDef)";
if (Inst.usesCustomInserter) OS << "|(1<<TID::UsesCustomInserter)";
- if (Inst.isVariadic) OS << "|(1<<TID::Variadic)";
+ if (Inst.Operands.isVariadic)OS << "|(1<<TID::Variadic)";
if (Inst.hasSideEffects) OS << "|(1<<TID::UnmodeledSideEffects)";
if (Inst.isAsCheapAsAMove) OS << "|(1<<TID::CheapAsAMove)";
if (Inst.hasExtraSrcRegAllocReq) OS << "|(1<<TID::ExtraSrcRegAllocReq)";
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index ba30d97eaa35..08f67284a279 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -14,6 +14,7 @@
#include "CodeGenTarget.h"
#include "IntrinsicEmitter.h"
#include "Record.h"
+#include "StringMatcher.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
using namespace llvm;
@@ -67,16 +68,19 @@ void IntrinsicEmitter::run(raw_ostream &OS) {
void IntrinsicEmitter::EmitPrefix(raw_ostream &OS) {
OS << "// VisualStudio defines setjmp as _setjmp\n"
- "#if defined(_MSC_VER) && defined(setjmp)\n"
- "#define setjmp_undefined_for_visual_studio\n"
- "#undef setjmp\n"
+ "#if defined(_MSC_VER) && defined(setjmp) && \\\n"
+ " !defined(setjmp_undefined_for_msvc)\n"
+ "# pragma push_macro(\"setjmp\")\n"
+ "# undef setjmp\n"
+ "# define setjmp_undefined_for_msvc\n"
"#endif\n\n";
}
void IntrinsicEmitter::EmitSuffix(raw_ostream &OS) {
- OS << "#if defined(_MSC_VER) && defined(setjmp_undefined_for_visual_studio)\n"
+ OS << "#if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc)\n"
"// let's return it to _setjmp state\n"
- "#define setjmp _setjmp\n"
+ "# pragma pop_macro(\"setjmp\")\n"
+ "# undef setjmp_undefined_for_msvc\n"
"#endif\n\n";
}
@@ -96,37 +100,48 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
void IntrinsicEmitter::
EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
- // Build a function name -> intrinsic name mapping.
- std::map<std::string, unsigned> IntMapping;
+ // Build a 'first character of function name' -> intrinsic # mapping.
+ std::map<char, std::vector<unsigned> > IntMapping;
for (unsigned i = 0, e = Ints.size(); i != e; ++i)
- IntMapping[Ints[i].Name] = i;
-
+ IntMapping[Ints[i].Name[5]].push_back(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(),
+ OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n";
+ OS << " switch (Name[5]) { // Dispatch on first letter.\n";
+ OS << " default: break;\n";
+ // Emit the intrinsic matching stuff by first letter.
+ for (std::map<char, std::vector<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";
+ OS << " case '" << I->first << "':\n";
+ std::vector<unsigned> &IntList = I->second;
+
+ // Emit all the overloaded intrinsics first, build a table of the
+ // non-overloaded ones.
+ std::vector<StringMatcher::StringPair> MatchTable;
+
+ for (unsigned i = 0, e = IntList.size(); i != e; ++i) {
+ unsigned IntNo = IntList[i];
+ std::string Result = "return " + TargetPrefix + "Intrinsic::" +
+ Ints[IntNo].EnumName + ";";
+
+ if (!Ints[IntNo].isOverloaded) {
+ MatchTable.push_back(std::make_pair(Ints[IntNo].Name.substr(6),Result));
+ continue;
+ }
+
+ // For overloaded intrinsics, only the prefix needs to match
+ std::string TheStr = Ints[IntNo].Name.substr(6);
+ TheStr += '.'; // Require "bswap." instead of bswap.
+ OS << " if (NameR.startswith(\"" << TheStr << "\")) "
+ << Result << '\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";
+ // Emit the matcher logic for the fixed length strings.
+ StringMatcher("NameR", MatchTable, OS).Emit(1);
+ OS << " break; // end of '" << I->first << "' case.\n";
}
+
OS << " }\n";
OS << "#endif\n\n";
}
@@ -180,6 +195,8 @@ static void EmitTypeForValueType(raw_ostream &OS, MVT::SimpleValueType VT) {
OS << "Type::getVoidTy(Context)";
} else if (VT == MVT::Metadata) {
OS << "Type::getMetadataTy(Context)";
+ } else if (VT == MVT::x86mmx) {
+ OS << "Type::getX86_MMXTy(Context)";
} else {
assert(false && "Unsupported ValueType!");
}
@@ -556,11 +573,13 @@ EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
OS << " return DoesNotAccessMemory;\n";
break;
case CodeGenIntrinsic::ReadArgMem:
+ OS << " return OnlyReadsArgumentPointees;\n";
+ break;
case CodeGenIntrinsic::ReadMem:
OS << " return OnlyReadsMemory;\n";
break;
case CodeGenIntrinsic::ReadWriteArgMem:
- OS << " return AccessesArguments;\n";
+ OS << " return OnlyAccessesArgumentPointees;\n";
break;
}
}
@@ -584,112 +603,22 @@ EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
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, raw_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,
raw_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);
- }
+ std::vector<StringMatcher::StringPair> Results;
- // 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";
+ for (std::map<std::string, std::string>::const_iterator I = BIM.begin(),
+ E = BIM.end(); I != E; ++I) {
+ std::string ResultCode =
+ "return " + TargetPrefix + "Intrinsic::" + I->second + ";";
+ Results.push_back(StringMatcher::StringPair(I->first, ResultCode));
}
- OS << " }\n";
+
+ StringMatcher("BuiltinName", Results, OS).Emit();
}
@@ -719,24 +648,20 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
if (TargetOnly) {
OS << "static " << TargetPrefix << "Intrinsic::ID "
<< "getIntrinsicForGCCBuiltin(const char "
- << "*TargetPrefix, const char *BuiltinName) {\n";
- OS << " " << TargetPrefix << "Intrinsic::ID IntrinsicID = ";
+ << "*TargetPrefixStr, const char *BuiltinNameStr) {\n";
} else {
OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char "
- << "*TargetPrefix, const char *BuiltinName) {\n";
- OS << " Intrinsic::ID IntrinsicID = ";
+ << "*TargetPrefixStr, const char *BuiltinNameStr) {\n";
}
- if (TargetOnly)
- OS << "(" << TargetPrefix<< "Intrinsic::ID)";
-
- OS << "Intrinsic::not_intrinsic;\n";
+ OS << " StringRef BuiltinName(BuiltinNameStr);\n";
+ OS << " StringRef TargetPrefix(TargetPrefixStr);\n\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 << "\")) ";
+ OS << "if (TargetPrefix == \"" << I->first << "\") ";
else
OS << "/* Target Independent Builtins */ ";
OS << "{\n";
@@ -745,7 +670,10 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
EmitTargetBuiltins(I->second, TargetPrefix, OS);
OS << " }\n";
}
- OS << " return IntrinsicID;\n";
+ OS << " return ";
+ if (!TargetPrefix.empty())
+ OS << "(" << TargetPrefix << "Intrinsic::ID)";
+ OS << "Intrinsic::not_intrinsic;\n";
OS << "}\n";
OS << "#endif\n\n";
}
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index 8b81e14cc26a..c40a39dff729 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -25,6 +25,7 @@
#include <string>
#include <typeinfo>
+
using namespace llvm;
namespace {
@@ -164,18 +165,6 @@ void CheckedIncrement(I& P, I E, S ErrorString) {
throw ErrorString;
}
-// apply is needed because C++'s syntax doesn't let us construct a function
-// object and call it in the same statement.
-template<typename F, typename T0>
-void apply(F Fun, T0& Arg0) {
- return Fun(Arg0);
-}
-
-template<typename F, typename T0, typename T1>
-void apply(F Fun, T0& Arg0, T1& Arg1) {
- return Fun(Arg0, Arg1);
-}
-
//===----------------------------------------------------------------------===//
/// Back-end specific code
@@ -779,14 +768,21 @@ public:
CheckNumberOfArguments(d, 2);
+ // Alias option store the aliased option name in the 'Help' field and do not
+ // have any properties.
if (OD.isAlias()) {
- // Aliases store the aliased option name in the 'Help' field.
OD.Help = InitPtrToString(d.getArg(1));
}
else {
processOptionProperties(d, OD);
}
+ // Switch options are ZeroOrMore by default.
+ if (OD.isSwitch()) {
+ if (!(OD.isOptional() || OD.isOneOrMore() || OD.isRequired()))
+ OD.setZeroOrMore();
+ }
+
OptDescs_.InsertDescription(OD);
}
@@ -809,13 +805,12 @@ void CollectOptionDescriptions (const RecordVector& V,
OptionDescriptions& OptDescs)
{
// For every OptionList:
- for (RecordVector::const_iterator B = V.begin(),
- E = V.end(); B!=E; ++B) {
+ for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B)
+ {
// Throws an exception if the value does not exist.
ListInit* PropList = (*B)->getValueAsListInit("options");
- // For every option description in this list:
- // collect the information and
+ // For every option description in this list: invoke AddOption.
std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
}
}
@@ -833,7 +828,7 @@ struct ToolDescription : public RefCountedBase<ToolDescription> {
StrVector InLanguage;
std::string InFileOption;
std::string OutFileOption;
- std::string OutLanguage;
+ StrVector OutLanguage;
std::string OutputSuffix;
unsigned Flags;
const Init* OnEmpty;
@@ -919,31 +914,24 @@ private:
toolDesc_.CmdLine = d.getArg(0);
}
- void onInLanguage (const DagInit& d) {
+ /// onInOutLanguage - Common implementation of on{In,Out}Language().
+ void onInOutLanguage (const DagInit& d, StrVector& OutVec) {
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));
+ // Copy strings to the output vector.
+ for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
+ OutVec.push_back(InitPtrToString(d.getArg(i)));
}
- 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(OutVec.begin(), OutVec.end());
+ StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end());
+ OutVec.erase(newE, OutVec.end());
+ }
- // Remove duplicates.
- std::sort(out.begin(), out.end());
- StrVector::iterator newE = std::unique(out.begin(), out.end());
- out.erase(newE, out.end());
- }
+
+ void onInLanguage (const DagInit& d) {
+ this->onInOutLanguage(d, toolDesc_.InLanguage);
}
void onJoin (const DagInit& d) {
@@ -952,8 +940,7 @@ private:
}
void onOutLanguage (const DagInit& d) {
- CheckNumberOfArguments(d, 1);
- toolDesc_.OutLanguage = InitPtrToString(d.getArg(0));
+ this->onInOutLanguage(d, toolDesc_.OutLanguage);
}
void onOutFileOption (const DagInit& d) {
@@ -1062,47 +1049,62 @@ void FilterNotInGraph (const DagVector& EdgeVector,
}
/// FillInToolToLang - Fills in two tables that map tool names to
-/// (input, output) languages. Helper function used by TypecheckGraph().
+/// input & output language names. Helper function used by TypecheckGraph().
void FillInToolToLang (const ToolDescriptions& ToolDescs,
StringMap<StringSet<> >& ToolToInLang,
- StringMap<std::string>& ToolToOutLang) {
+ StringMap<StringSet<> >& 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;
+ for (StrVector::const_iterator B = D.OutLanguage.begin(),
+ E = D.OutLanguage.end(); B != E; ++B)
+ ToolToOutLang[D.Name].insert(*B);
}
}
+/// Intersect - Is set intersection non-empty?
+bool Intersect (const StringSet<>& S1, const StringSet<>& S2) {
+ for (StringSet<>::const_iterator B = S1.begin(), E = S1.end(); B != E; ++B) {
+ if (S2.count(B->first()) != 0)
+ return true;
+ }
+ return false;
+}
+
/// TypecheckGraph - Check that names for output and input languages
/// on all edges do match.
void TypecheckGraph (const DagVector& EdgeVector,
const ToolDescriptions& ToolDescs) {
StringMap<StringSet<> > ToolToInLang;
- StringMap<std::string> ToolToOutLang;
+ StringMap<StringSet<> > ToolToOutLang;
FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
- StringMap<std::string>::iterator IAE = ToolToOutLang.end();
- StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
const DagInit* Edge = *B;
const std::string& NodeA = InitPtrToString(Edge->getArg(0));
const std::string& NodeB = InitPtrToString(Edge->getArg(1));
- StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
+ StringMap<StringSet<> >::iterator IA = ToolToOutLang.find(NodeA);
StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
+ if (NodeB == "root")
+ throw "Edges back to the root are not allowed!";
+
if (NodeA != "root") {
- if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
+ if (IA == ToolToOutLang.end())
+ throw NodeA + ": no output language defined!";
+ if (IB == ToolToInLang.end())
+ throw NodeB + ": no input language defined!";
+
+ if (!Intersect(IA->second, IB->second)) {
throw "Edge " + NodeA + "->" + NodeB
+ ": output->input language mismatch";
+ }
}
-
- if (NodeB == "root")
- throw "Edges back to the root are not allowed!";
}
}
@@ -1178,25 +1180,20 @@ class ExtractOptionNames {
if (ActionName == "forward" || ActionName == "forward_as" ||
ActionName == "forward_value" ||
ActionName == "forward_transformed_value" ||
- ActionName == "switch_on" || ActionName == "any_switch_on" ||
- ActionName == "parameter_equals" ||
- ActionName == "element_in_list" || ActionName == "not_empty" ||
- ActionName == "empty") {
+ ActionName == "parameter_equals" || ActionName == "element_in_list") {
CheckNumberOfArguments(Stmt, 1);
Init* Arg = Stmt.getArg(0);
- if (typeid(*Arg) == typeid(StringInit)) {
- const std::string& Name = InitPtrToString(Arg);
- OptionNames_.insert(Name);
- }
- else {
- // It's a list.
- const ListInit& List = InitPtrToList(Arg);
- for (ListInit::const_iterator B = List.begin(), E = List.end();
- B != E; ++B) {
- const std::string& Name = InitPtrToString(*B);
- OptionNames_.insert(Name);
- }
+ if (typeid(*Arg) == typeid(StringInit))
+ OptionNames_.insert(InitPtrToString(Arg));
+ }
+ else if (ActionName == "any_switch_on" || ActionName == "switch_on" ||
+ ActionName == "any_not_empty" || ActionName == "any_empty" ||
+ ActionName == "not_empty" || ActionName == "empty") {
+ for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
+ Init* Arg = Stmt.getArg(i);
+ if (typeid(*Arg) == typeid(StringInit))
+ OptionNames_.insert(InitPtrToString(Arg));
}
}
else if (ActionName == "and" || ActionName == "or" || ActionName == "not") {
@@ -1211,6 +1208,7 @@ public:
{}
void operator()(const Init* Statement) {
+ // Statement is either a dag, or a list of dags.
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
@@ -1291,24 +1289,20 @@ bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) {
return false;
}
-/// EmitListTest - Helper function used by EmitCaseTest1ArgList().
+/// EmitMultipleArgumentTest - Helper function used by
+/// EmitCaseTestMultipleArgs()
template <typename F>
-void EmitListTest(const ListInit& L, const char* LogicOp,
- F Callback, raw_ostream& O)
+void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp,
+ F Callback, raw_ostream& O)
{
- // This is a lot like EmitLogicalOperationTest, but works on ListInits instead
- // of Dags...
- bool isFirst = true;
- for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) {
- if (isFirst)
- isFirst = false;
- else
- O << ' ' << LogicOp << ' ';
- Callback(InitPtrToString(*B), O);
+ for (unsigned i = 0, NumArgs = D.getNumArgs(); i < NumArgs; ++i) {
+ if (i != 0)
+ O << ' ' << LogicOp << ' ';
+ Callback(InitPtrToString(D.getArg(i)), O);
}
}
-// Callbacks for use with EmitListTest.
+// Callbacks for use with EmitMultipleArgumentTest
class EmitSwitchOn {
const OptionDescriptions& OptDescs_;
@@ -1346,54 +1340,48 @@ public:
};
-/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg();
-bool EmitCaseTest1ArgList(const std::string& TestName,
- const DagInit& d,
- const OptionDescriptions& OptDescs,
- raw_ostream& O) {
- const ListInit& L = InitPtrToList(d.getArg(0));
-
+/// EmitCaseTestMultipleArgs - Helper function used by EmitCaseTest1Arg()
+bool EmitCaseTestMultipleArgs (const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ raw_ostream& O) {
if (TestName == "any_switch_on") {
- EmitListTest(L, "||", EmitSwitchOn(OptDescs), O);
+ EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O);
return true;
}
else if (TestName == "switch_on") {
- EmitListTest(L, "&&", EmitSwitchOn(OptDescs), O);
+ EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O);
return true;
}
else if (TestName == "any_not_empty") {
- EmitListTest(L, "||", EmitEmptyTest(true, OptDescs), O);
+ EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O);
return true;
}
else if (TestName == "any_empty") {
- EmitListTest(L, "||", EmitEmptyTest(false, OptDescs), O);
+ EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O);
return true;
}
else if (TestName == "not_empty") {
- EmitListTest(L, "&&", EmitEmptyTest(true, OptDescs), O);
+ EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O);
return true;
}
else if (TestName == "empty") {
- EmitListTest(L, "&&", EmitEmptyTest(false, OptDescs), O);
+ EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O);
return true;
}
return false;
}
-/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg();
-bool EmitCaseTest1ArgStr(const std::string& TestName,
- const DagInit& d,
- const OptionDescriptions& OptDescs,
- raw_ostream& O) {
- const std::string& OptName = InitPtrToString(d.getArg(0));
+/// EmitCaseTest1Arg - Helper function used by EmitCaseTest1OrMoreArgs()
+bool EmitCaseTest1Arg (const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ raw_ostream& O) {
+ const std::string& Arg = InitPtrToString(d.getArg(0));
- if (TestName == "switch_on") {
- apply(EmitSwitchOn(OptDescs), OptName, O);
- return true;
- }
- else if (TestName == "input_languages_contain") {
- O << "InLangs.count(\"" << OptName << "\") != 0";
+ if (TestName == "input_languages_contain") {
+ O << "InLangs.count(\"" << Arg << "\") != 0";
return true;
}
else if (TestName == "in_language") {
@@ -1401,28 +1389,22 @@ bool EmitCaseTest1ArgStr(const std::string& TestName,
// 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") {
- bool EmitNegate = (TestName == "not_empty");
- apply(EmitEmptyTest(EmitNegate, OptDescs), OptName, O);
+ O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"';
return true;
}
return false;
}
-/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler();
-bool EmitCaseTest1Arg(const std::string& TestName,
- const DagInit& d,
- const OptionDescriptions& OptDescs,
- raw_ostream& O) {
+/// EmitCaseTest1OrMoreArgs - Helper function used by
+/// EmitCaseConstructHandler()
+bool EmitCaseTest1OrMoreArgs(const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ raw_ostream& O) {
CheckNumberOfArguments(d, 1);
- if (typeid(*d.getArg(0)) == typeid(ListInit))
- return EmitCaseTest1ArgList(TestName, d, OptDescs, O);
- else
- return EmitCaseTest1ArgStr(TestName, d, OptDescs, O);
+ return EmitCaseTest1Arg(TestName, d, OptDescs, O) ||
+ EmitCaseTestMultipleArgs(TestName, d, OptDescs, O);
}
/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler().
@@ -1466,10 +1448,10 @@ void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
O << '(';
- for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
- const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
+ for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
+ const DagInit& InnerTest = InitPtrToDag(d.getArg(i));
EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
- if (j != NumArgs - 1) {
+ if (i != NumArgs - 1) {
O << ")\n";
O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " (";
}
@@ -1503,7 +1485,7 @@ void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
EmitLogicalNot(d, IndentLevel, OptDescs, O);
else if (EmitCaseTest0Args(TestName, O))
return;
- else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
+ else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O))
return;
else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
return;
@@ -1550,10 +1532,12 @@ public:
{}
void operator() (const Init* Statement, unsigned IndentLevel) {
+ // Is this a nested 'case'?
+ bool IsCase = dynamic_cast<const DagInit*>(Statement) &&
+ GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case";
- // Ignore nested 'case' DAG.
- if (!(dynamic_cast<const DagInit*>(Statement) &&
- GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case")) {
+ // If so, ignore it, it is handled by our caller, WalkCase.
+ if (!IsCase) {
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
@@ -2250,11 +2234,8 @@ void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
O.indent(Indent2) << "return InputLanguages_;\n";
O.indent(Indent1) << "}\n\n";
- if (D.OutLanguage.empty())
- throw "Tool " + D.Name + " has no 'out_language' property!";
-
- O.indent(Indent1) << "const char* OutputLanguage() const {\n";
- O.indent(Indent2) << "return \"" << D.OutLanguage << "\";\n";
+ O.indent(Indent1) << "const char** OutputLanguages() const {\n";
+ O.indent(Indent2) << "return OutputLanguages_;\n";
O.indent(Indent1) << "}\n\n";
}
@@ -2299,17 +2280,28 @@ void EmitWorksOnEmptyMethod (const ToolDescription& D,
O.indent(Indent1) << "}\n\n";
}
+/// EmitStrArray - Emit definition of a 'const char**' static member
+/// variable. Helper used by EmitStaticMemberDefinitions();
+void EmitStrArray(const std::string& Name, const std::string& VarName,
+ const StrVector& StrVec, raw_ostream& O) {
+ O << "const char* " << Name << "::" << VarName << "[] = {";
+ for (StrVector::const_iterator B = StrVec.begin(), E = StrVec.end();
+ B != E; ++B)
+ O << '\"' << *B << "\", ";
+ O << "0};\n";
+}
+
/// EmitStaticMemberDefinitions - Emit static member definitions for a
/// given Tool class.
void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
if (D.InLanguage.empty())
throw "Tool " + D.Name + " has no 'in_language' property!";
+ if (D.OutLanguage.empty())
+ throw "Tool " + D.Name + " has no 'out_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";
+ EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O);
+ EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O);
+ O << '\n';
}
/// EmitToolClassDefinition - Emit a Tool class definition.
@@ -2327,7 +2319,8 @@ void EmitToolClassDefinition (const ToolDescription& D,
O << "Tool";
O << " {\nprivate:\n";
- O.indent(Indent1) << "static const char* InputLanguages_[];\n\n";
+ O.indent(Indent1) << "static const char* InputLanguages_[];\n";
+ O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n";
O << "public:\n";
EmitNameMethod(D, O);
@@ -2448,21 +2441,13 @@ class EmitPreprocessOptionsCallback :
const OptionDescriptions& OptDescs_;
- void onListOrDag(const DagInit& d, HandlerImpl h,
- unsigned IndentLevel, raw_ostream& O) const
+ void onEachArgument(const DagInit& d, HandlerImpl h,
+ unsigned IndentLevel, raw_ostream& O) const
{
CheckNumberOfArguments(d, 1);
- const Init* I = d.getArg(0);
- // If I is a list, apply h to each element.
- if (typeid(*I) == typeid(ListInit)) {
- const ListInit& L = *static_cast<const ListInit*>(I);
- for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B)
- ((this)->*(h))(*B, IndentLevel, O);
- }
- // Otherwise, apply h to I.
- else {
- ((this)->*(h))(I, IndentLevel, O);
+ for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
+ ((this)->*(h))(d.getArg(i), IndentLevel, O);
}
}
@@ -2489,16 +2474,17 @@ class EmitPreprocessOptionsCallback :
void onUnsetOption(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
- this->onListOrDag(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
- IndentLevel, O);
+ this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
+ IndentLevel, O);
}
- void onSetOptionImpl(const DagInit& d,
+ void onSetOptionImpl(const DagInit& D,
unsigned IndentLevel, raw_ostream& O) const {
- CheckNumberOfArguments(d, 2);
- const std::string& OptName = InitPtrToString(d.getArg(0));
- const Init* Value = d.getArg(1);
+ CheckNumberOfArguments(D, 2);
+
+ const std::string& OptName = InitPtrToString(D.getArg(0));
const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
+ const Init* Value = D.getArg(1);
if (OptDesc.isList()) {
const ListInit& List = InitPtrToList(Value);
@@ -2528,7 +2514,7 @@ class EmitPreprocessOptionsCallback :
<< " = \"" << Str << "\";\n";
}
else {
- throw "Can't apply 'set_option' to alias option -" + OptName + " !";
+ throw "Can't apply 'set_option' to alias option '" + OptName + "'!";
}
}
@@ -2548,15 +2534,22 @@ class EmitPreprocessOptionsCallback :
{
CheckNumberOfArguments(d, 1);
- // Two arguments: (set_option "parameter", VALUE), where VALUE can be a
- // boolean, a string or a string list.
- if (d.getNumArgs() > 1)
- this->onSetOptionImpl(d, IndentLevel, O);
- // One argument: (set_option "switch")
- // or (set_option ["switch1", "switch2", ...])
- else
- this->onListOrDag(d, &EmitPreprocessOptionsCallback::onSetSwitch,
- IndentLevel, O);
+ // 2-argument form: (set_option "A", true), (set_option "B", "C"),
+ // (set_option "D", ["E", "F"])
+ if (d.getNumArgs() == 2) {
+ const OptionDescription& OptDesc =
+ OptDescs_.FindOption(InitPtrToString(d.getArg(0)));
+ const Init* Opt2 = d.getArg(1);
+
+ if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) {
+ this->onSetOptionImpl(d, IndentLevel, O);
+ return;
+ }
+ }
+
+ // Multiple argument form: (set_option "A"), (set_option "B", "C", "D")
+ this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch,
+ IndentLevel, O);
}
public:
@@ -2661,10 +2654,11 @@ void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
{
O << "int PopulateLanguageMap (LanguageMap& langMap) {\n";
- // For each LangMap:
+ // For each LanguageMap:
const RecordVector& LangMaps =
Records.getAllDerivedDefinitions("LanguageMap");
+ // Call DoEmitPopulateLanguageMap.
for (RecordVector::const_iterator B = LangMaps.begin(),
E = LangMaps.end(); B!=E; ++B) {
ListInit* LangMap = (*B)->getValueAsListInit("map");
@@ -2899,7 +2893,7 @@ public:
return;
}
- // We're invoked on a command line.
+ // We're invoked on a command line string.
this->onCmdLine(InitPtrToString(Arg));
}
@@ -3041,7 +3035,8 @@ void CheckDriverData(DriverData& Data) {
CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
}
-void EmitDriverCode(const DriverData& Data, raw_ostream& O) {
+void EmitDriverCode(const DriverData& Data,
+ raw_ostream& O, RecordKeeper &Records) {
// Emit file header.
EmitIncludes(O);
@@ -3102,7 +3097,7 @@ void LLVMCConfigurationEmitter::run (raw_ostream &O) {
CheckDriverData(Data);
this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O);
- EmitDriverCode(Data, O);
+ EmitDriverCode(Data, O, Records);
} 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
index b37b83fb9255..0f2ff3719678 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.h
+++ b/utils/TableGen/LLVMCConfigurationEmitter.h
@@ -21,8 +21,10 @@ namespace llvm {
/// LLVMCConfigurationEmitter - TableGen backend that generates
/// configuration code for LLVMC.
class LLVMCConfigurationEmitter : public TableGenBackend {
+ RecordKeeper &Records;
public:
- explicit LLVMCConfigurationEmitter(RecordKeeper&) {}
+ explicit LLVMCConfigurationEmitter(RecordKeeper &records) :
+ Records(records) {}
// run - Output the asmwriter, returning true on failure.
void run(raw_ostream &o);
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
index f27cd995783e..c01b6602faa3 100644
--- a/utils/TableGen/Makefile
+++ b/utils/TableGen/Makefile
@@ -9,7 +9,7 @@
LEVEL = ../..
TOOLNAME = tblgen
-USEDLIBS = LLVMSupport.a LLVMSystem.a
+USEDLIBS = LLVMSupport.a
REQUIRES_EH := 1
REQUIRES_RTTI := 1
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 0a12f3766699..64224d9e51d0 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -8,17 +8,18 @@
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting arm_neon.h, which includes
-// a declaration and definition of each function specified by the ARM NEON
+// a declaration and definition of each function specified by the ARM NEON
// compiler interface. See ARM document DUI0348B.
//
// Each NEON instruction is implemented in terms of 1 or more functions which
-// are suffixed with the element type of the input vectors. Functions may be
+// are suffixed with the element type of the input vectors. Functions may be
// implemented in terms of generic vector operations such as +, *, -, etc. or
// by calling a __builtin_-prefixed function which will be handled by clang's
// CodeGen library.
//
// Additional validation code can be generated by this file when runHeader() is
-// called, rather than the normal run() entry point.
+// called, rather than the normal run() entry point. A complete set of tests
+// for Neon intrinsics can be generated by calling the runTests() entry point.
//
//===----------------------------------------------------------------------===//
@@ -38,11 +39,11 @@ static void ParseTypes(Record *r, std::string &s,
SmallVectorImpl<StringRef> &TV) {
const char *data = s.data();
int len = 0;
-
+
for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
continue;
-
+
switch (data[len]) {
case 'c':
case 's':
@@ -72,6 +73,8 @@ static char Widen(const char t) {
return 'i';
case 'i':
return 'l';
+ case 'h':
+ return 'f';
default: throw "unhandled type in widen!";
}
return '\0';
@@ -89,7 +92,7 @@ static char Narrow(const char t) {
return 'i';
case 'f':
return 'h';
- default: throw "unhandled type in widen!";
+ default: throw "unhandled type in narrow!";
}
return '\0';
}
@@ -98,25 +101,25 @@ static char Narrow(const char t) {
/// the quad-vector, polynomial, or unsigned modifiers set.
static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
unsigned off = 0;
-
+
// remember quad.
if (ty[off] == 'Q') {
quad = true;
++off;
}
-
+
// remember poly.
if (ty[off] == 'P') {
poly = true;
++off;
}
-
+
// remember unsigned.
if (ty[off] == 'U') {
usgn = true;
++off;
}
-
+
// base type to get the type string for.
return ty[off];
}
@@ -134,7 +137,12 @@ static char ModType(const char mod, char type, bool &quad, bool &poly,
break;
case 'u':
usgn = true;
+ poly = false;
+ if (type == 'f')
+ type = 'i';
+ break;
case 'x':
+ usgn = false;
poly = false;
if (type == 'f')
type = 'i';
@@ -155,6 +163,10 @@ static char ModType(const char mod, char type, bool &quad, bool &poly,
case 'n':
type = Widen(type);
break;
+ case 'i':
+ type = 'i';
+ scal = true;
+ break;
case 'l':
type = 'l';
scal = true;
@@ -189,36 +201,31 @@ static char ModType(const char mod, char type, bool &quad, bool &poly,
}
/// TypeString - for a modifier and type, generate the name of the typedef for
-/// that type. If generic is true, emit the generic vector type rather than
-/// the public NEON type. QUc -> uint8x8_t / __neon_uint8x8_t.
-static std::string TypeString(const char mod, StringRef typestr,
- bool generic = false) {
+/// that type. QUc -> uint8x8_t.
+static std::string TypeString(const char mod, StringRef typestr) {
bool quad = false;
bool poly = false;
bool usgn = false;
bool scal = false;
bool cnst = false;
bool pntr = false;
-
+
if (mod == 'v')
return "void";
if (mod == 'i')
return "int";
-
+
// base type to get the type string for.
char type = ClassifyType(typestr, quad, poly, usgn);
-
+
// Based on the modifying character, change the type and width if necessary.
type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
-
+
SmallString<128> s;
-
- if (generic)
- s += "__neon_";
-
+
if (usgn)
s.push_back('u');
-
+
switch (type) {
case 'c':
s += poly ? "poly8" : "int8";
@@ -267,16 +274,16 @@ static std::string TypeString(const char mod, StringRef typestr,
s += "x3";
if (mod == '4')
s += "x4";
-
+
// Append _t, finishing the type string typedef type.
s += "_t";
-
+
if (cnst)
s += " const";
-
+
if (pntr)
s += " *";
-
+
return s.str();
}
@@ -291,23 +298,25 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
bool scal = false;
bool cnst = false;
bool pntr = false;
-
+
if (mod == 'v')
- return "v";
+ return "v"; // void
if (mod == 'i')
- return "i";
-
+ return "i"; // int
+
// base type to get the type string for.
char type = ClassifyType(typestr, quad, poly, usgn);
-
+
// Based on the modifying character, change the type and width if necessary.
type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
+ // All pointers are void* pointers. Change type to 'v' now.
if (pntr) {
usgn = false;
poly = false;
type = 'v';
}
+ // Treat half-float ('h') types as unsigned short ('s') types.
if (type == 'h') {
type = 's';
usgn = true;
@@ -319,12 +328,14 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
if (usgn)
s.push_back('U');
-
- if (type == 'l')
+ else if (type == 'c')
+ s.push_back('S'); // make chars explicitly signed
+
+ if (type == 'l') // 64-bit long
s += "LLi";
else
s.push_back(type);
-
+
if (cnst)
s.push_back('C');
if (pntr)
@@ -337,8 +348,8 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
// returning structs of 2, 3, or 4 vectors which are returned in a sret-like
// fashion, storing them to a pointer arg.
if (ret) {
- if (mod == '2' || mod == '3' || mod == '4')
- return "vv*";
+ if (mod >= '2' && mod <= '4')
+ return "vv*"; // void result with void* first argument
if (mod == 'f' || (ck != ClassB && type == 'f'))
return quad ? "V4f" : "V2f";
if (ck != ClassB && type == 's')
@@ -347,17 +358,17 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
return quad ? "V4i" : "V2i";
if (ck != ClassB && type == 'l')
return quad ? "V2LLi" : "V1LLi";
-
- return quad ? "V16c" : "V8c";
- }
+
+ return quad ? "V16Sc" : "V8Sc";
+ }
// Non-return array types are passed as individual vectors.
if (mod == '2')
- return quad ? "V16cV16c" : "V8cV8c";
+ return quad ? "V16ScV16Sc" : "V8ScV8Sc";
if (mod == '3')
- return quad ? "V16cV16cV16c" : "V8cV8cV8c";
+ return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
if (mod == '4')
- return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c";
+ return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
if (mod == 'f' || (ck != ClassB && type == 'f'))
return quad ? "V4f" : "V2f";
@@ -367,71 +378,25 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr,
return quad ? "V4i" : "V2i";
if (ck != ClassB && type == 'l')
return quad ? "V2LLi" : "V1LLi";
-
- return quad ? "V16c" : "V8c";
-}
-/// StructTag - generate the name of the struct tag for a type.
-/// These names are mandated by ARM's ABI.
-static std::string StructTag(StringRef typestr) {
- bool quad = false;
- bool poly = false;
- bool usgn = false;
-
- // base type to get the type string for.
- char type = ClassifyType(typestr, quad, poly, usgn);
-
- SmallString<128> s;
- s += "__simd";
- s += quad ? "128_" : "64_";
- if (usgn)
- s.push_back('u');
-
- switch (type) {
- case 'c':
- s += poly ? "poly8" : "int8";
- break;
- case 's':
- s += poly ? "poly16" : "int16";
- break;
- case 'i':
- s += "int32";
- break;
- case 'l':
- s += "int64";
- break;
- case 'h':
- s += "float16";
- break;
- case 'f':
- s += "float32";
- break;
- default:
- throw "unhandled type!";
- break;
- }
-
- // Append _t, finishing the struct tag name.
- s += "_t";
-
- return s.str();
+ return quad ? "V16Sc" : "V8Sc";
}
-/// MangleName - Append a type or width suffix to a base neon function name,
+/// MangleName - Append a type or width suffix to a base neon function name,
/// and insert a 'q' in the appropriate location if the operation works on
/// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
static std::string MangleName(const std::string &name, StringRef typestr,
ClassKind ck) {
if (name == "vcvt_f32_f16")
return name;
-
+
bool quad = false;
bool poly = false;
bool usgn = false;
char type = ClassifyType(typestr, quad, poly, usgn);
std::string s = name;
-
+
switch (type) {
case 'c':
switch (ck) {
@@ -487,8 +452,8 @@ static std::string MangleName(const std::string &name, StringRef typestr,
}
if (ck == ClassB)
s += "_v";
-
- // Insert a 'q' before the first '_' character so that it ends up before
+
+ // Insert a 'q' before the first '_' character so that it ends up before
// _lane or _n on vector-scalar operations.
if (quad) {
size_t pos = s.find('_');
@@ -501,177 +466,344 @@ static std::string MangleName(const std::string &name, StringRef typestr,
static std::string GenArgs(const std::string &proto, StringRef typestr) {
bool define = proto.find('i') != std::string::npos;
char arg = 'a';
-
+
std::string s;
s += "(";
-
+
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
- if (!define) {
- s += TypeString(proto[i], typestr);
- s.push_back(' ');
+ if (define) {
+ // Immediate macro arguments are used directly instead of being assigned
+ // to local temporaries; prepend an underscore prefix to make their
+ // names consistent with the local temporaries.
+ if (proto[i] == 'i')
+ s += "__";
+ } else {
+ s += TypeString(proto[i], typestr) + " __";
}
s.push_back(arg);
if ((i + 1) < e)
s += ", ";
}
-
+
s += ")";
return s;
}
-static std::string Duplicate(unsigned nElts, StringRef typestr,
+// Macro arguments are not type-checked like inline function arguments, so
+// assign them to local temporaries to get the right type checking.
+static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
+ char arg = 'a';
+ std::string s;
+
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ // Do not create a temporary for an immediate argument.
+ // That would defeat the whole point of using a macro!
+ if (proto[i] == 'i') continue;
+
+ s += TypeString(proto[i], typestr) + " __";
+ s.push_back(arg);
+ s += " = (";
+ s.push_back(arg);
+ s += "); ";
+ }
+
+ s += "\\\n ";
+ return s;
+}
+
+// Use the vmovl builtin to sign-extend or zero-extend a vector.
+static std::string Extend(StringRef typestr, const std::string &a) {
+ std::string s;
+ s = MangleName("vmovl", typestr, ClassS);
+ s += "(" + a + ")";
+ return s;
+}
+
+static std::string Duplicate(unsigned nElts, StringRef typestr,
const std::string &a) {
std::string s;
-
- s = "(__neon_" + TypeString('d', typestr) + "){ ";
+
+ s = "(" + TypeString('d', typestr) + "){ ";
for (unsigned i = 0; i != nElts; ++i) {
s += a;
if ((i + 1) < nElts)
s += ", ";
}
s += " }";
-
+
return s;
}
-// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
-// If structTypes is true, the NEON types are structs of vector types rather
-// than vector types, and the call becomes "a.val + b.val"
-static std::string GenOpString(OpKind op, const std::string &proto,
- StringRef typestr, bool structTypes = true) {
- bool dummy, quad = false;
+static std::string SplatLane(unsigned nElts, const std::string &vec,
+ const std::string &lane) {
+ std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
+ for (unsigned i = 0; i < nElts; ++i)
+ s += ", " + lane;
+ s += ")";
+ return s;
+}
+
+static unsigned GetNumElements(StringRef typestr, bool &quad) {
+ quad = false;
+ bool dummy = false;
char type = ClassifyType(typestr, quad, dummy, dummy);
unsigned nElts = 0;
switch (type) {
- case 'c': nElts = 8; break;
- case 's': nElts = 4; break;
- case 'i': nElts = 2; break;
- case 'l': nElts = 1; break;
- case 'h': nElts = 4; break;
- case 'f': nElts = 2; break;
+ case 'c': nElts = 8; break;
+ case 's': nElts = 4; break;
+ case 'i': nElts = 2; break;
+ case 'l': nElts = 1; break;
+ case 'h': nElts = 4; break;
+ case 'f': nElts = 2; break;
+ default:
+ throw "unhandled type!";
+ break;
}
-
+ if (quad) nElts <<= 1;
+ return nElts;
+}
+
+// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
+static std::string GenOpString(OpKind op, const std::string &proto,
+ StringRef typestr) {
+ bool quad;
+ unsigned nElts = GetNumElements(typestr, quad);
+
+ // If this builtin takes an immediate argument, we need to #define it rather
+ // than use a standard declaration, so that SemaChecking can range check
+ // the immediate passed by the user.
+ bool define = proto.find('i') != std::string::npos;
+
std::string ts = TypeString(proto[0], typestr);
- std::string s = ts + " r; r";
-
- if (structTypes)
- s += ".val";
-
- s += " = ";
-
- std::string a, b, c;
- if (proto.size() > 1)
- a = (structTypes && proto[1] != 'l' && proto[1] != 's') ? "a.val" : "a";
- b = structTypes ? "b.val" : "b";
- c = structTypes ? "c.val" : "c";
-
+ std::string s;
+ if (!define) {
+ s = "return ";
+ }
+
switch(op) {
case OpAdd:
- s += a + " + " + b;
+ s += "__a + __b;";
+ break;
+ case OpAddl:
+ s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
+ break;
+ case OpAddw:
+ s += "__a + " + Extend(typestr, "__b") + ";";
break;
case OpSub:
- s += a + " - " + b;
+ s += "__a - __b;";
+ break;
+ case OpSubl:
+ s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
+ break;
+ case OpSubw:
+ s += "__a - " + Extend(typestr, "__b") + ";";
break;
case OpMulN:
- b = Duplicate(nElts << (int)quad, typestr, "b");
+ s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
+ break;
+ case OpMulLane:
+ s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
+ break;
case OpMul:
- s += a + " * " + b;
+ s += "__a * __b;";
+ break;
+ case OpMullN:
+ s += Extend(typestr, "__a") + " * " +
+ Extend(typestr, Duplicate(nElts << (int)quad, typestr, "__b")) + ";";
+ break;
+ case OpMullLane:
+ s += Extend(typestr, "__a") + " * " +
+ Extend(typestr, SplatLane(nElts, "__b", "__c")) + ";";
+ break;
+ case OpMull:
+ s += Extend(typestr, "__a") + " * " + Extend(typestr, "__b") + ";";
break;
case OpMlaN:
- c = Duplicate(nElts << (int)quad, typestr, "c");
+ s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
+ break;
+ case OpMlaLane:
+ s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
case OpMla:
- s += a + " + ( " + b + " * " + c + " )";
+ s += "__a + (__b * __c);";
+ break;
+ case OpMlalN:
+ s += "__a + (" + Extend(typestr, "__b") + " * " +
+ Extend(typestr, Duplicate(nElts, typestr, "__c")) + ");";
+ break;
+ case OpMlalLane:
+ s += "__a + (" + Extend(typestr, "__b") + " * " +
+ Extend(typestr, SplatLane(nElts, "__c", "__d")) + ");";
+ break;
+ case OpMlal:
+ s += "__a + (" + Extend(typestr, "__b") + " * " +
+ Extend(typestr, "__c") + ");";
break;
case OpMlsN:
- c = Duplicate(nElts << (int)quad, typestr, "c");
+ s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
+ break;
+ case OpMlsLane:
+ s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
case OpMls:
- s += a + " - ( " + b + " * " + c + " )";
+ s += "__a - (__b * __c);";
+ break;
+ case OpMlslN:
+ s += "__a - (" + Extend(typestr, "__b") + " * " +
+ Extend(typestr, Duplicate(nElts, typestr, "__c")) + ");";
+ break;
+ case OpMlslLane:
+ s += "__a - (" + Extend(typestr, "__b") + " * " +
+ Extend(typestr, SplatLane(nElts, "__c", "__d")) + ");";
+ break;
+ case OpMlsl:
+ s += "__a - (" + Extend(typestr, "__b") + " * " +
+ Extend(typestr, "__c") + ");";
+ break;
+ case OpQDMullLane:
+ s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
+ case OpQDMlalLane:
+ s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
+ SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpQDMlslLane:
+ s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
+ SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpQDMulhLane:
+ s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
+ case OpQRDMulhLane:
+ s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
break;
case OpEq:
- s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
+ s += "(" + ts + ")(__a == __b);";
break;
case OpGe:
- s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
+ s += "(" + ts + ")(__a >= __b);";
break;
case OpLe:
- s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
+ s += "(" + ts + ")(__a <= __b);";
break;
case OpGt:
- s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
+ s += "(" + ts + ")(__a > __b);";
break;
case OpLt:
- s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
+ s += "(" + ts + ")(__a < __b);";
break;
case OpNeg:
- s += " -" + a;
+ s += " -__a;";
break;
case OpNot:
- s += " ~" + a;
+ s += " ~__a;";
break;
case OpAnd:
- s += a + " & " + b;
+ s += "__a & __b;";
break;
case OpOr:
- s += a + " | " + b;
+ s += "__a | __b;";
break;
case OpXor:
- s += a + " ^ " + b;
+ s += "__a ^ __b;";
break;
case OpAndNot:
- s += a + " & ~" + b;
+ s += "__a & ~__b;";
break;
case OpOrNot:
- s += a + " | ~" + b;
+ s += "__a | ~__b;";
break;
case OpCast:
- s += "(__neon_" + ts + ")" + a;
+ s += "(" + ts + ")__a;";
break;
case OpConcat:
- s += "__builtin_shufflevector((__neon_int64x1_t)" + a;
- s += ", (__neon_int64x1_t)" + b + ", 0, 1)";
+ s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
+ s += ", (int64x1_t)__b, 0, 1);";
break;
case OpHi:
- s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[1])";
+ s += "(" + ts +
+ ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);";
break;
case OpLo:
- s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[0])";
+ s += "(" + ts +
+ ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);";
break;
case OpDup:
- s += Duplicate(nElts << (int)quad, typestr, a);
+ s += Duplicate(nElts, typestr, "__a") + ";";
+ break;
+ case OpDupLane:
+ s += SplatLane(nElts, "__a", "__b") + ";";
break;
case OpSelect:
// ((0 & 1) | (~0 & 2))
+ s += "(" + ts + ")";
ts = TypeString(proto[1], typestr);
- s += "( " + a + " & (__neon_" + ts + ")" + b + ") | ";
- s += "(~" + a + " & (__neon_" + ts + ")" + c + ")";
+ s += "((__a & (" + ts + ")__b) | ";
+ s += "(~__a & (" + ts + ")__c));";
break;
case OpRev16:
- s += "__builtin_shufflevector(" + a + ", " + a;
- for (unsigned i = 2; i <= nElts << (int)quad; i += 2)
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = 2; i <= nElts; i += 2)
for (unsigned j = 0; j != 2; ++j)
s += ", " + utostr(i - j - 1);
- s += ")";
+ s += ");";
break;
- case OpRev32:
- nElts >>= 1;
- s += "__builtin_shufflevector(" + a + ", " + a;
- for (unsigned i = nElts; i <= nElts << (1 + (int)quad); i += nElts)
- for (unsigned j = 0; j != nElts; ++j)
+ case OpRev32: {
+ unsigned WordElts = nElts >> (1 + (int)quad);
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = WordElts; i <= nElts; i += WordElts)
+ for (unsigned j = 0; j != WordElts; ++j)
s += ", " + utostr(i - j - 1);
- s += ")";
+ s += ");";
break;
- case OpRev64:
- s += "__builtin_shufflevector(" + a + ", " + a;
- for (unsigned i = nElts; i <= nElts << (int)quad; i += nElts)
- for (unsigned j = 0; j != nElts; ++j)
+ }
+ case OpRev64: {
+ unsigned DblWordElts = nElts >> (int)quad;
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
+ for (unsigned j = 0; j != DblWordElts; ++j)
s += ", " + utostr(i - j - 1);
- s += ")";
+ s += ");";
+ break;
+ }
+ case OpAbdl: {
+ std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
+ if (typestr[0] != 'U') {
+ // vabd results are always unsigned and must be zero-extended.
+ std::string utype = "U" + typestr.str();
+ s += "(" + TypeString(proto[0], typestr) + ")";
+ abd = "(" + TypeString('d', utype) + ")" + abd;
+ s += Extend(utype, abd) + ";";
+ } else {
+ s += Extend(typestr, abd) + ";";
+ }
+ break;
+ }
+ case OpAba:
+ s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
break;
+ case OpAbal: {
+ s += "__a + ";
+ std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)";
+ if (typestr[0] != 'U') {
+ // vabd results are always unsigned and must be zero-extended.
+ std::string utype = "U" + typestr.str();
+ s += "(" + TypeString(proto[0], typestr) + ")";
+ abd = "(" + TypeString('d', utype) + ")" + abd;
+ s += Extend(utype, abd) + ";";
+ } else {
+ s += Extend(typestr, abd) + ";";
+ }
+ break;
+ }
default:
throw "unknown OpKind!";
break;
}
- s += "; return r;";
return s;
}
@@ -688,10 +820,10 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
bool scal = false;
bool cnst = false;
bool pntr = false;
-
+
// Base type to get the type string for.
char type = ClassifyType(typestr, quad, poly, usgn);
-
+
// Based on the modifying character, change the type and width if necessary.
type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
@@ -699,9 +831,9 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
ret |= 0x08;
if (quad && proto[1] != 'g')
ret |= 0x10;
-
+
switch (type) {
- case 'c':
+ case 'c':
ret |= poly ? 5 : 0;
break;
case 's':
@@ -727,65 +859,45 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
}
// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
-// If structTypes is true, the NEON types are structs of vector types rather
-// than vector types, and the call becomes __builtin_neon_cls(a.val)
static std::string GenBuiltin(const std::string &name, const std::string &proto,
- StringRef typestr, ClassKind ck,
- bool structTypes = true) {
- bool dummy, quad = false;
- char type = ClassifyType(typestr, quad, dummy, dummy);
- unsigned nElts = 0;
- switch (type) {
- case 'c': nElts = 8; break;
- case 's': nElts = 4; break;
- case 'i': nElts = 2; break;
- case 'l': nElts = 1; break;
- case 'h': nElts = 4; break;
- case 'f': nElts = 2; break;
- }
- if (quad) nElts <<= 1;
-
- char arg = 'a';
+ StringRef typestr, ClassKind ck) {
std::string s;
// If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
// sret-like argument.
- bool sret = (proto[0] == '2' || proto[0] == '3' || proto[0] == '4');
+ bool sret = (proto[0] >= '2' && proto[0] <= '4');
// If this builtin takes an immediate argument, we need to #define it rather
// than use a standard declaration, so that SemaChecking can range check
// the immediate passed by the user.
bool define = proto.find('i') != std::string::npos;
- // If all types are the same size, bitcasting the args will take care
- // of arg checking. The actual signedness etc. will be taken care of with
- // special enums.
+ // Check if the prototype has a scalar operand with the type of the vector
+ // elements. If not, bitcasting the args will take care of arg checking.
+ // The actual signedness etc. will be taken care of with special enums.
if (proto.find('s') == std::string::npos)
ck = ClassB;
if (proto[0] != 'v') {
std::string ts = TypeString(proto[0], typestr);
-
+
if (define) {
if (sret)
- s += "({ " + ts + " r; ";
- else if (proto[0] != 's')
- s += "(" + ts + "){(__neon_" + ts + ")";
+ s += ts + " r; ";
+ else
+ s += "(" + ts + ")";
} else if (sret) {
s += ts + " r; ";
} else {
- s += ts + " r; r";
- if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l')
- s += ".val";
-
- s += " = ";
+ s += "return (" + ts + ")";
}
}
-
+
bool splat = proto.find('a') != std::string::npos;
-
+
s += "__builtin_neon_";
if (splat) {
+ // Call the non-splat builtin: chop off the "_n" suffix from the name.
std::string vname(name, 0, name.size()-2);
s += MangleName(vname, typestr, ck);
} else {
@@ -797,17 +909,32 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto,
// builtins.
if (sret)
s += "&r, ";
-
+
+ char arg = 'a';
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
std::string args = std::string(&arg, 1);
- if (define)
- args = "(" + args + ")";
-
+
+ // Use the local temporaries instead of the macro arguments.
+ args = "__" + args;
+
+ bool argQuad = false;
+ bool argPoly = false;
+ bool argUsgn = false;
+ bool argScalar = false;
+ bool dummy = false;
+ char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
+ argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
+ dummy, dummy);
+
// Handle multiple-vector values specially, emitting each subvector as an
// argument to the __builtin.
- if (structTypes && (proto[i] == '2' || proto[i] == '3' || proto[i] == '4')){
+ if (proto[i] >= '2' && proto[i] <= '4') {
+ // Check if an explicit cast is needed.
+ if (argType != 'c' || argPoly || argUsgn)
+ args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
+
for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
- s += args + ".val[" + utostr(vi) + "].val";
+ s += args + ".val[" + utostr(vi) + "]";
if ((vi + 1) < ve)
s += ", ";
}
@@ -816,77 +943,158 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto,
continue;
}
-
- if (splat && (i + 1) == e)
- s += Duplicate(nElts, typestr, args);
- else
- s += args;
-
- if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
- proto[i] != 'p' && proto[i] != 'c' && proto[i] != 'a') {
- s += ".val";
+
+ if (splat && (i + 1) == e)
+ args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
+
+ // Check if an explicit cast is needed.
+ if ((splat || !argScalar) &&
+ ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
+ std::string argTypeStr = "c";
+ if (ck != ClassB)
+ argTypeStr = argType;
+ if (argQuad)
+ argTypeStr = "Q" + argTypeStr;
+ args = "(" + TypeString('d', argTypeStr) + ")" + args;
}
+
+ s += args;
if ((i + 1) < e)
s += ", ";
}
-
+
// Extra constant integer to hold type class enum for this function, e.g. s8
if (ck == ClassB)
s += ", " + utostr(GetNeonEnum(proto, typestr));
-
- if (define)
- s += ")";
- else
- s += ");";
- if (proto[0] != 'v') {
- if (define) {
- if (sret)
- s += "; r; })";
- else if (proto[0] != 's')
- s += "}";
- } else {
+ s += ");";
+
+ if (proto[0] != 'v' && sret) {
+ if (define)
+ s += " r;";
+ else
s += " return r;";
- }
}
return s;
}
-static std::string GenBuiltinDef(const std::string &name,
+static std::string GenBuiltinDef(const std::string &name,
const std::string &proto,
StringRef typestr, ClassKind ck) {
std::string s("BUILTIN(__builtin_neon_");
- // If all types are the same size, bitcasting the args will take care
+ // If all types are the same size, bitcasting the args will take care
// of arg checking. The actual signedness etc. will be taken care of with
// special enums.
if (proto.find('s') == std::string::npos)
ck = ClassB;
-
+
s += MangleName(name, typestr, ck);
s += ", \"";
-
+
for (unsigned i = 0, e = proto.size(); i != e; ++i)
s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
// Extra constant integer to hold type class enum for this function, e.g. s8
if (ck == ClassB)
s += "i";
-
+
s += "\", \"n\")";
return s;
}
+static std::string GenIntrinsic(const std::string &name,
+ const std::string &proto,
+ StringRef outTypeStr, StringRef inTypeStr,
+ OpKind kind, ClassKind classKind) {
+ assert(!proto.empty() && "");
+ bool define = proto.find('i') != std::string::npos;
+ std::string s;
+
+ // static always inline + return type
+ if (define)
+ s += "#define ";
+ else
+ s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
+
+ // Function name with type suffix
+ std::string mangledName = MangleName(name, outTypeStr, ClassS);
+ if (outTypeStr != inTypeStr) {
+ // If the input type is different (e.g., for vreinterpret), append a suffix
+ // for the input type. String off a "Q" (quad) prefix so that MangleName
+ // does not insert another "q" in the name.
+ unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
+ StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
+ mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
+ }
+ s += mangledName;
+
+ // Function arguments
+ s += GenArgs(proto, inTypeStr);
+
+ // Definition.
+ if (define) {
+ s += " __extension__ ({ \\\n ";
+ s += GenMacroLocals(proto, inTypeStr);
+ } else {
+ s += " { \\\n ";
+ }
+
+ if (kind != OpNone)
+ s += GenOpString(kind, proto, outTypeStr);
+ else
+ s += GenBuiltin(name, proto, outTypeStr, classKind);
+ if (define)
+ s += " })";
+ else
+ s += " }";
+ s += "\n";
+ return s;
+}
+
/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
/// is comprised of type definitions and function declarations.
void NeonEmitter::run(raw_ostream &OS) {
- EmitSourceFileHeader("ARM NEON Header", OS);
-
- // FIXME: emit license into file?
-
+ OS <<
+ "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
+ "---===\n"
+ " *\n"
+ " * Permission is hereby granted, free of charge, to any person obtaining "
+ "a copy\n"
+ " * of this software and associated documentation files (the \"Software\"),"
+ " to deal\n"
+ " * in the Software without restriction, including without limitation the "
+ "rights\n"
+ " * to use, copy, modify, merge, publish, distribute, sublicense, "
+ "and/or sell\n"
+ " * copies of the Software, and to permit persons to whom the Software is\n"
+ " * furnished to do so, subject to the following conditions:\n"
+ " *\n"
+ " * The above copyright notice and this permission notice shall be "
+ "included in\n"
+ " * all copies or substantial portions of the Software.\n"
+ " *\n"
+ " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
+ "EXPRESS OR\n"
+ " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
+ "MERCHANTABILITY,\n"
+ " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
+ "SHALL THE\n"
+ " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
+ "OTHER\n"
+ " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
+ "ARISING FROM,\n"
+ " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
+ "DEALINGS IN\n"
+ " * THE SOFTWARE.\n"
+ " *\n"
+ " *===--------------------------------------------------------------------"
+ "---===\n"
+ " */\n\n";
+
OS << "#ifndef __ARM_NEON_H\n";
OS << "#define __ARM_NEON_H\n\n";
-
+
OS << "#ifndef __ARM_NEON__\n";
OS << "#error \"NEON support not enabled\"\n";
OS << "#endif\n\n";
@@ -895,8 +1103,8 @@ void NeonEmitter::run(raw_ostream &OS) {
// Emit NEON-specific scalar typedefs.
OS << "typedef float float32_t;\n";
- OS << "typedef uint8_t poly8_t;\n";
- OS << "typedef uint16_t poly16_t;\n";
+ OS << "typedef int8_t poly8_t;\n";
+ OS << "typedef int16_t poly16_t;\n";
OS << "typedef uint16_t float16_t;\n";
// Emit Neon vector typedefs.
@@ -905,105 +1113,105 @@ void NeonEmitter::run(raw_ostream &OS) {
ParseTypes(0, TypedefTypes, TDTypeVec);
// Emit vector typedefs.
- for (unsigned v = 1; v != 5; ++v) {
- for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
- bool dummy, quad = false;
- (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
- OS << "typedef __attribute__(( __vector_size__(";
-
- OS << utostr(8*v*(quad ? 2 : 1)) << ") )) ";
- if (!quad)
- OS << " ";
-
- OS << TypeString('s', TDTypeVec[i]);
- OS << " __neon_";
-
- char t = (v == 1) ? 'd' : '0' + v;
- OS << TypeString(t, TDTypeVec[i]) << ";\n";
- }
+ for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
+ bool dummy, quad = false, poly = false;
+ (void) ClassifyType(TDTypeVec[i], quad, poly, dummy);
+ if (poly)
+ OS << "typedef __attribute__((neon_polyvector_type(";
+ else
+ OS << "typedef __attribute__((neon_vector_type(";
+
+ unsigned nElts = GetNumElements(TDTypeVec[i], quad);
+ OS << utostr(nElts) << "))) ";
+ if (nElts < 10)
+ OS << " ";
+
+ OS << TypeString('s', TDTypeVec[i]);
+ OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
}
OS << "\n";
// Emit struct typedefs.
- for (unsigned vi = 1; vi != 5; ++vi) {
+ for (unsigned vi = 2; vi != 5; ++vi) {
for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
- std::string ts = TypeString('d', TDTypeVec[i], vi == 1);
- std::string vs = TypeString((vi > 1) ? '0' + vi : 'd', TDTypeVec[i]);
- std::string tag = (vi > 1) ? vs : StructTag(TDTypeVec[i]);
- OS << "typedef struct " << tag << " {\n";
+ std::string ts = TypeString('d', TDTypeVec[i]);
+ std::string vs = TypeString('0' + vi, TDTypeVec[i]);
+ OS << "typedef struct " << vs << " {\n";
OS << " " << ts << " val";
- if (vi > 1)
- OS << "[" << utostr(vi) << "]";
- OS << ";\n} " << vs << ";\n\n";
+ OS << "[" << utostr(vi) << "]";
+ OS << ";\n} ";
+ OS << vs << ";\n\n";
}
}
-
+
OS << "#define __ai static __attribute__((__always_inline__))\n\n";
std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
-
- // Unique the return+pattern types, and assign them.
+
+ // Emit vmovl and vabd intrinsics first so they can be used by other
+ // intrinsics. (Some of the saturating multiply instructions are also
+ // used to implement the corresponding "_lane" variants, but tablegen
+ // sorts the records into alphabetical order so that the "_lane" variants
+ // come after the intrinsics they use.)
+ emitIntrinsic(OS, Records.getDef("VMOVL"));
+ emitIntrinsic(OS, Records.getDef("VABD"));
+
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
- std::string name = LowercaseString(R->getName());
- std::string Proto = R->getValueAsString("Prototype");
- std::string Types = R->getValueAsString("Types");
-
- SmallVector<StringRef, 16> TypeVec;
- ParseTypes(R, Types, TypeVec);
-
- OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
-
- bool define = Proto.find('i') != std::string::npos;
-
- for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
- assert(!Proto.empty() && "");
-
- // static always inline + return type
- if (define)
- OS << "#define";
- else
- OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
-
- // Function name with type suffix
- OS << " " << MangleName(name, TypeVec[ti], ClassS);
-
- // Function arguments
- OS << GenArgs(Proto, TypeVec[ti]);
-
- // Definition.
- if (define)
- OS << " ";
- else
- OS << " { ";
-
- if (k != OpNone) {
- OS << GenOpString(k, Proto, TypeVec[ti]);
- } else {
- if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
-
- ClassKind ck = ClassMap[R->getSuperClasses()[1]];
-
- if (ck == ClassNone)
- throw TGError(R->getLoc(), "Builtin has no class kind");
- OS << GenBuiltin(name, Proto, TypeVec[ti], ck);
- }
- if (!define)
- OS << " }";
- OS << "\n";
- }
- OS << "\n";
+ if (R->getName() != "VMOVL" && R->getName() != "VABD")
+ emitIntrinsic(OS, R);
}
+
OS << "#undef __ai\n\n";
OS << "#endif /* __ARM_NEON_H */\n";
}
-static unsigned RangeFromType(StringRef typestr) {
+/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
+/// intrinsics specified by record R.
+void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
+ std::string name = R->getValueAsString("Name");
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
+
+ ClassKind classKind = ClassNone;
+ if (R->getSuperClasses().size() >= 2)
+ classKind = ClassMap[R->getSuperClasses()[1]];
+ if (classKind == ClassNone && kind == OpNone)
+ throw TGError(R->getLoc(), "Builtin has no class kind");
+
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ if (kind == OpReinterpret) {
+ bool outQuad = false;
+ bool dummy = false;
+ (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
+ for (unsigned srcti = 0, srcte = TypeVec.size();
+ srcti != srcte; ++srcti) {
+ bool inQuad = false;
+ (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
+ if (srcti == ti || inQuad != outQuad)
+ continue;
+ OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
+ OpCast, ClassS);
+ }
+ } else {
+ OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti],
+ kind, classKind);
+ }
+ }
+ OS << "\n";
+}
+
+static unsigned RangeFromType(const char mod, StringRef typestr) {
// base type to get the type string for.
bool quad = false, dummy = false;
char type = ClassifyType(typestr, quad, dummy, dummy);
-
+ type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
+
switch (type) {
case 'c':
return (8 << (int)quad) - 1;
@@ -1031,7 +1239,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
StringMap<OpKind> EmittedMap;
-
+
// Generate BuiltinsARM.def for NEON
OS << "#ifdef GET_NEON_BUILTINS\n";
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
@@ -1041,22 +1249,22 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
continue;
std::string Proto = R->getValueAsString("Prototype");
-
+
// Functions with 'a' (the splat code) in the type prototype should not get
// their own builtin as they use the non-splat variant.
if (Proto.find('a') != std::string::npos)
continue;
-
+
std::string Types = R->getValueAsString("Types");
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
-
+
if (R->getSuperClasses().size() < 2)
throw TGError(R->getLoc(), "Builtin has no class kind");
-
- std::string name = LowercaseString(R->getName());
+
+ std::string name = R->getValueAsString("Name");
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
-
+
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
// Generate the BuiltinsARM.def declaration for this builtin, ensuring
// that each unique BUILTIN() macro appears only once in the output
@@ -1064,13 +1272,13 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
if (EmittedMap.count(bd))
continue;
-
+
EmittedMap[bd] = OpNone;
OS << bd << "\n";
}
}
OS << "#endif\n\n";
-
+
// Generate the overloaded type checking code for SemaChecking.cpp
OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
@@ -1078,34 +1286,34 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
if (k != OpNone)
continue;
-
+
std::string Proto = R->getValueAsString("Prototype");
std::string Types = R->getValueAsString("Types");
- std::string name = LowercaseString(R->getName());
-
+ std::string name = R->getValueAsString("Name");
+
// Functions with 'a' (the splat code) in the type prototype should not get
// their own builtin as they use the non-splat variant.
if (Proto.find('a') != std::string::npos)
continue;
-
+
// Functions which have a scalar argument cannot be overloaded, no need to
// check them if we are emitting the type checking code.
if (Proto.find('s') != std::string::npos)
continue;
-
+
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
-
+
if (R->getSuperClasses().size() < 2)
throw TGError(R->getLoc(), "Builtin has no class kind");
-
+
int si = -1, qi = -1;
unsigned mask = 0, qmask = 0;
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
// Generate the switch case(s) for this builtin for the type validation.
bool quad = false, poly = false, usgn = false;
(void) ClassifyType(TypeVec[ti], quad, poly, usgn);
-
+
if (quad) {
qi = ti;
qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
@@ -1115,64 +1323,67 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
}
}
if (mask)
- OS << "case ARM::BI__builtin_neon_"
- << MangleName(name, TypeVec[si], ClassB)
- << ": mask = " << "0x" << utohexstr(mask) << "; break;\n";
+ OS << "case ARM::BI__builtin_neon_"
+ << MangleName(name, TypeVec[si], ClassB)
+ << ": mask = " << "0x" << utohexstr(mask) << "; break;\n";
if (qmask)
- OS << "case ARM::BI__builtin_neon_"
- << MangleName(name, TypeVec[qi], ClassB)
- << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n";
+ OS << "case ARM::BI__builtin_neon_"
+ << MangleName(name, TypeVec[qi], ClassB)
+ << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n";
}
OS << "#endif\n\n";
-
+
// Generate the intrinsic range checking code for shift/lane immediates.
OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
-
+
OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
if (k != OpNone)
continue;
-
- std::string name = LowercaseString(R->getName());
+
+ std::string name = R->getValueAsString("Name");
std::string Proto = R->getValueAsString("Prototype");
std::string Types = R->getValueAsString("Types");
-
+
// Functions with 'a' (the splat code) in the type prototype should not get
// their own builtin as they use the non-splat variant.
if (Proto.find('a') != std::string::npos)
continue;
-
+
// Functions which do not have an immediate do not need to have range
// checking code emitted.
- if (Proto.find('i') == std::string::npos)
+ size_t immPos = Proto.find('i');
+ if (immPos == std::string::npos)
continue;
-
+
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
-
+
if (R->getSuperClasses().size() < 2)
throw TGError(R->getLoc(), "Builtin has no class kind");
-
+
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
-
+
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
std::string namestr, shiftstr, rangestr;
-
+
// Builtins which are overloaded by type will need to have their upper
// bound computed at Sema time based on the type constant.
if (Proto.find('s') == std::string::npos) {
ck = ClassB;
if (R->getValueAsBit("isShift")) {
shiftstr = ", true";
-
+
// Right shifts have an 'r' in the name, left shifts do not.
if (name.find('r') != std::string::npos)
rangestr = "l = 1; ";
}
rangestr += "u = RFT(TV" + shiftstr + ")";
} else {
- rangestr = "u = " + utostr(RangeFromType(TypeVec[ti]));
+ // The immediate generally refers to a lane in the preceding argument.
+ assert(immPos > 0 && "unexpected immediate operand");
+ rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti]));
}
// Make sure cases appear only once by uniquing them in a string map.
namestr = MangleName(name, TypeVec[ti], ck);
@@ -1182,13 +1393,13 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
// Calculate the index of the immediate that should be range checked.
unsigned immidx = 0;
-
+
// Builtins that return a struct of multiple vectors have an extra
// leading arg for the struct return.
- if (Proto[0] == '2' || Proto[0] == '3' || Proto[0] == '4')
+ if (Proto[0] >= '2' && Proto[0] <= '4')
++immidx;
-
- // Add one to the index for each argument until we reach the immediate
+
+ // Add one to the index for each argument until we reach the immediate
// to be checked. Structs of vectors are passed as multiple arguments.
for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
switch (Proto[ii]) {
@@ -1199,9 +1410,113 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
case 'i': ie = ii + 1; break;
}
}
- OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck)
+ OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck)
<< ": i = " << immidx << "; " << rangestr << "; break;\n";
}
}
OS << "#endif\n\n";
}
+
+/// GenTest - Write out a test for the intrinsic specified by the name and
+/// type strings, including the embedded patterns for FileCheck to match.
+static std::string GenTest(const std::string &name,
+ const std::string &proto,
+ StringRef outTypeStr, StringRef inTypeStr,
+ bool isShift) {
+ assert(!proto.empty() && "");
+ std::string s;
+
+ // Function name with type suffix
+ std::string mangledName = MangleName(name, outTypeStr, ClassS);
+ if (outTypeStr != inTypeStr) {
+ // If the input type is different (e.g., for vreinterpret), append a suffix
+ // for the input type. String off a "Q" (quad) prefix so that MangleName
+ // does not insert another "q" in the name.
+ unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
+ StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
+ mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
+ }
+
+ // Emit the FileCheck patterns.
+ s += "// CHECK: test_" + mangledName + "\n";
+ // s += "// CHECK: \n"; // FIXME: + expected instruction opcode.
+
+ // Emit the start of the test function.
+ s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
+ char arg = 'a';
+ std::string comma;
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ // Do not create arguments for values that must be immediate constants.
+ if (proto[i] == 'i')
+ continue;
+ s += comma + TypeString(proto[i], inTypeStr) + " ";
+ s.push_back(arg);
+ comma = ", ";
+ }
+ s += ") { \\\n ";
+
+ if (proto[0] != 'v')
+ s += "return ";
+ s += mangledName + "(";
+ arg = 'a';
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ if (proto[i] == 'i') {
+ // For immediate operands, test the maximum value.
+ if (isShift)
+ s += "1"; // FIXME
+ else
+ // The immediate generally refers to a lane in the preceding argument.
+ s += utostr(RangeFromType(proto[i-1], inTypeStr));
+ } else {
+ s.push_back(arg);
+ }
+ if ((i + 1) < e)
+ s += ", ";
+ }
+ s += ");\n}\n\n";
+ return s;
+}
+
+/// runTests - Write out a complete set of tests for all of the Neon
+/// intrinsics.
+void NeonEmitter::runTests(raw_ostream &OS) {
+ OS <<
+ "// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n"
+ "// RUN: -target-cpu cortex-a9 -ffreestanding -S -o - %s | FileCheck %s\n"
+ "\n"
+ "#include <arm_neon.h>\n"
+ "\n";
+
+ std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+ std::string name = R->getValueAsString("Name");
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+ bool isShift = R->getValueAsBit("isShift");
+
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ if (kind == OpReinterpret) {
+ bool outQuad = false;
+ bool dummy = false;
+ (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
+ for (unsigned srcti = 0, srcte = TypeVec.size();
+ srcti != srcte; ++srcti) {
+ bool inQuad = false;
+ (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
+ if (srcti == ti || inQuad != outQuad)
+ continue;
+ OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift);
+ }
+ } else {
+ OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift);
+ }
+ }
+ OS << "\n";
+ }
+}
+
diff --git a/utils/TableGen/NeonEmitter.h b/utils/TableGen/NeonEmitter.h
index 6c6760d732fa..1e6fcbf555df 100644
--- a/utils/TableGen/NeonEmitter.h
+++ b/utils/TableGen/NeonEmitter.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting arm_neon.h, which includes
-// a declaration and definition of each function specified by the ARM NEON
+// a declaration and definition of each function specified by the ARM NEON
// compiler interface. See ARM document DUI0348B.
//
//===----------------------------------------------------------------------===//
@@ -24,13 +24,34 @@
enum OpKind {
OpNone,
OpAdd,
+ OpAddl,
+ OpAddw,
OpSub,
+ OpSubl,
+ OpSubw,
OpMul,
+ OpMull,
OpMla,
+ OpMlal,
OpMls,
+ OpMlsl,
OpMulN,
+ OpMullN,
OpMlaN,
OpMlsN,
+ OpMlalN,
+ OpMlslN,
+ OpMulLane,
+ OpMullLane,
+ OpMlaLane,
+ OpMlsLane,
+ OpMlalLane,
+ OpMlslLane,
+ OpQDMullLane,
+ OpQDMlalLane,
+ OpQDMlslLane,
+ OpQDMulhLane,
+ OpQRDMulhLane,
OpEq,
OpGe,
OpLe,
@@ -46,40 +67,66 @@ enum OpKind {
OpCast,
OpConcat,
OpDup,
+ OpDupLane,
OpHi,
OpLo,
OpSelect,
OpRev16,
OpRev32,
- OpRev64
+ OpRev64,
+ OpReinterpret,
+ OpAbdl,
+ OpAba,
+ OpAbal
};
enum ClassKind {
ClassNone,
- ClassI,
- ClassS,
- ClassW,
- ClassB
+ ClassI, // generic integer instruction, e.g., "i8" suffix
+ ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
+ ClassW, // width-specific instruction, e.g., "8" suffix
+ ClassB // bitcast arguments with enum argument to specify type
};
namespace llvm {
-
+
class NeonEmitter : public TableGenBackend {
RecordKeeper &Records;
StringMap<OpKind> OpMap;
DenseMap<Record*, ClassKind> ClassMap;
-
+
public:
NeonEmitter(RecordKeeper &R) : Records(R) {
OpMap["OP_NONE"] = OpNone;
OpMap["OP_ADD"] = OpAdd;
+ OpMap["OP_ADDL"] = OpAddl;
+ OpMap["OP_ADDW"] = OpAddw;
OpMap["OP_SUB"] = OpSub;
+ OpMap["OP_SUBL"] = OpSubl;
+ OpMap["OP_SUBW"] = OpSubw;
OpMap["OP_MUL"] = OpMul;
+ OpMap["OP_MULL"] = OpMull;
OpMap["OP_MLA"] = OpMla;
+ OpMap["OP_MLAL"] = OpMlal;
OpMap["OP_MLS"] = OpMls;
+ OpMap["OP_MLSL"] = OpMlsl;
OpMap["OP_MUL_N"] = OpMulN;
+ OpMap["OP_MULL_N"]= OpMullN;
OpMap["OP_MLA_N"] = OpMlaN;
OpMap["OP_MLS_N"] = OpMlsN;
+ OpMap["OP_MLAL_N"] = OpMlalN;
+ OpMap["OP_MLSL_N"] = OpMlslN;
+ OpMap["OP_MUL_LN"]= OpMulLane;
+ OpMap["OP_MULL_LN"] = OpMullLane;
+ OpMap["OP_MLA_LN"]= OpMlaLane;
+ OpMap["OP_MLS_LN"]= OpMlsLane;
+ OpMap["OP_MLAL_LN"] = OpMlalLane;
+ OpMap["OP_MLSL_LN"] = OpMlslLane;
+ OpMap["OP_QDMULL_LN"] = OpQDMullLane;
+ OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
+ OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
+ OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
+ OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
OpMap["OP_EQ"] = OpEq;
OpMap["OP_GE"] = OpGe;
OpMap["OP_LE"] = OpLe;
@@ -97,10 +144,15 @@ namespace llvm {
OpMap["OP_HI"] = OpHi;
OpMap["OP_LO"] = OpLo;
OpMap["OP_DUP"] = OpDup;
+ OpMap["OP_DUP_LN"] = OpDupLane;
OpMap["OP_SEL"] = OpSelect;
OpMap["OP_REV16"] = OpRev16;
OpMap["OP_REV32"] = OpRev32;
OpMap["OP_REV64"] = OpRev64;
+ OpMap["OP_REINT"] = OpReinterpret;
+ OpMap["OP_ABDL"] = OpAbdl;
+ OpMap["OP_ABA"] = OpAba;
+ OpMap["OP_ABAL"] = OpAbal;
Record *SI = R.getClass("SInst");
Record *II = R.getClass("IInst");
@@ -109,14 +161,20 @@ namespace llvm {
ClassMap[II] = ClassI;
ClassMap[WI] = ClassW;
}
-
+
// run - Emit arm_neon.h.inc
void run(raw_ostream &o);
// runHeader - Emit all the __builtin prototypes used in arm_neon.h
void runHeader(raw_ostream &o);
+
+ // runTests - Emit tests for all the Neon intrinsics.
+ void runTests(raw_ostream &o);
+
+ private:
+ void emitIntrinsic(raw_ostream &OS, Record *R);
};
-
+
} // End llvm namespace
#endif
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
index dc793586fbee..abbbafed09d8 100644
--- a/utils/TableGen/Record.cpp
+++ b/utils/TableGen/Record.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Record.h"
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringExtras.h"
@@ -59,26 +59,34 @@ Init *BitsRecTy::convertValue(UnsetInit *UI) {
}
Init *BitsRecTy::convertValue(BitInit *UI) {
- if (Size != 1) return 0; // Can only convert single bit...
+ 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...
+/// canFitInBitfield - Return true if the number of bits is large enough to hold
+/// the integer value.
+static bool canFitInBitfield(int64_t Value, unsigned NumBits) {
if (Value >= 0) {
- if (Value & ~((1LL << Size)-1))
- return 0;
- } else {
- if ((Value >> Size) != -1 || ((Value & (1LL << (Size-1))) == 0))
- return 0;
+ if (Value & ~((1LL << NumBits) - 1))
+ return false;
+ } else if ((Value >> NumBits) != -1 || (Value & (1LL << (NumBits-1))) == 0) {
+ return false;
}
+ return true;
+}
+
+/// 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 (!canFitInBitfield(Value, Size))
+ return 0;
+
BitsInit *Ret = new BitsInit(Size);
for (unsigned i = 0; i != Size; ++i)
Ret->setBit(i, new BitInit(Value & (1LL << i)));
@@ -88,7 +96,7 @@ Init *BitsRecTy::convertValue(IntInit *II) {
Init *BitsRecTy::convertValue(BitsInit *BI) {
// If the number of bits is right, return it. Otherwise we need to expand or
- // truncate...
+ // truncate.
if (BI->getNumBits() == Size) return BI;
return 0;
}
@@ -101,12 +109,56 @@ Init *BitsRecTy::convertValue(TypedInit *VI) {
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;
}
+ if (TernOpInit *Tern = dynamic_cast<TernOpInit*>(VI)) {
+ if (Tern->getOpcode() == TernOpInit::IF) {
+ Init *LHS = Tern->getLHS();
+ Init *MHS = Tern->getMHS();
+ Init *RHS = Tern->getRHS();
+
+ IntInit *MHSi = dynamic_cast<IntInit*>(MHS);
+ IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
+
+ if (MHSi && RHSi) {
+ int64_t MHSVal = MHSi->getValue();
+ int64_t RHSVal = RHSi->getValue();
+
+ if (canFitInBitfield(MHSVal, Size) && canFitInBitfield(RHSVal, Size)) {
+ BitsInit *Ret = new BitsInit(Size);
+
+ for (unsigned i = 0; i != Size; ++i)
+ Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS,
+ new IntInit((MHSVal & (1LL << i)) ? 1 : 0),
+ new IntInit((RHSVal & (1LL << i)) ? 1 : 0),
+ VI->getType()));
+
+ return Ret;
+ }
+ } else {
+ BitsInit *MHSbs = dynamic_cast<BitsInit*>(MHS);
+ BitsInit *RHSbs = dynamic_cast<BitsInit*>(RHS);
+
+ if (MHSbs && RHSbs) {
+ BitsInit *Ret = new BitsInit(Size);
+
+ for (unsigned i = 0; i != Size; ++i)
+ Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS,
+ MHSbs->getBit(i),
+ RHSbs->getBit(i),
+ VI->getType()));
+
+ return Ret;
+ }
+ }
+ }
+ }
+
return 0;
}
@@ -152,16 +204,6 @@ Init *StringRecTy::convertValue(BinOpInit *BO) {
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);
}
@@ -236,16 +278,6 @@ Init *DagRecTy::convertValue(BinOpInit *BO) {
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;
}
@@ -518,9 +550,8 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
// From TGParser::ParseIDValue
if (CurRec) {
if (const RecordVal *RV = CurRec->getValue(Name)) {
- if (RV->getType() != getType()) {
- throw "type mismatch in nameconcat";
- }
+ if (RV->getType() != getType())
+ throw "type mismatch in cast";
return new VarInit(Name, RV->getType());
}
@@ -529,9 +560,8 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
const RecordVal *RV = CurRec->getValue(TemplateArgName);
assert(RV && "Template arg doesn't exist??");
- if (RV->getType() != getType()) {
- throw "type mismatch in nameconcat";
- }
+ if (RV->getType() != getType())
+ throw "type mismatch in cast";
return new VarInit(TemplateArgName, RV->getType());
}
@@ -543,15 +573,14 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
const RecordVal *RV = CurMultiClass->Rec.getValue(MCName);
assert(RV && "Template arg doesn't exist??");
- if (RV->getType() != getType()) {
- throw "type mismatch in nameconcat";
- }
+ if (RV->getType() != getType())
+ throw "type mismatch in cast";
return new VarInit(MCName, RV->getType());
}
}
- if (Record *D = Records.getDef(Name))
+ if (Record *D = (CurRec->getRecords()).getDef(Name))
return new DefInit(D);
errs() << "Variable not defined: '" + Name + "'\n";
@@ -561,7 +590,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
}
break;
}
- case CAR: {
+ case HEAD: {
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
if (LHSl) {
if (LHSl->getSize() == 0) {
@@ -572,7 +601,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
}
break;
}
- case CDR: {
+ case TAIL: {
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
if (LHSl) {
if (LHSl->getSize() == 0) {
@@ -585,7 +614,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
}
break;
}
- case LNULL: {
+ case EMPTY: {
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
if (LHSl) {
if (LHSl->getSize() == 0) {
@@ -621,9 +650,9 @@ 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;
+ case HEAD: Result = "!head"; break;
+ case TAIL: Result = "!tail"; break;
+ case EMPTY: Result = "!empty"; break;
}
return Result + "(" + LHS->getAsString() + ")";
}
@@ -660,57 +689,6 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
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);
-
- errs() << "Variable not defined in !nameconcat: '" + Name + "'\n";
- assert(0 && "Variable not found in !nameconcat");
- return 0;
- }
- break;
- }
case EQ: {
// try to fold eq comparison for 'bit' and 'int', otherwise fallback
// to string objects.
@@ -771,8 +749,6 @@ std::string BinOpInit::getAsString() const {
case SRL: Result = "!srl"; break;
case EQ: Result = "!eq"; break;
case STRCONCAT: Result = "!strconcat"; break;
- case NAMECONCAT:
- Result = "!nameconcat<" + getType()->getAsString() + ">"; break;
}
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
}
@@ -1042,7 +1018,7 @@ RecTy *TypedInit::getFieldType(const std::string &FieldName) const {
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...
+ if (T == 0) return 0; // Cannot subscript a non-bits variable.
unsigned NumBits = T->getNumBits();
BitsInit *BI = new BitsInit(Bits.size());
@@ -1058,7 +1034,7 @@ Init *TypedInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
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 (T == 0) return 0; // Cannot subscript a non-list variable.
if (Elements.size() == 1)
return new VarListElementInit(this, Elements[0]);
@@ -1211,7 +1187,7 @@ Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV,
assert(Bit < BI->getNumBits() && "Bit reference out of range!");
Init *B = BI->getBit(Bit);
- if (dynamic_cast<BitInit*>(B)) // If the bit is set...
+ if (dynamic_cast<BitInit*>(B)) // If the bit is set.
return B; // Replace the VarBitInit with it.
}
return 0;
@@ -1303,14 +1279,14 @@ void RecordVal::print(raw_ostream &OS, bool PrintSem) const {
unsigned Record::LastID = 0;
void Record::setName(const std::string &Name) {
- if (Records.getDef(getName()) == this) {
- Records.removeDef(getName());
+ if (TrackedRecords.getDef(getName()) == this) {
+ TrackedRecords.removeDef(getName());
this->Name = Name;
- Records.addDef(this);
+ TrackedRecords.addDef(this);
} else {
- Records.removeClass(getName());
+ TrackedRecords.removeClass(getName());
this->Name = Name;
- Records.addClass(this);
+ TrackedRecords.addClass(this);
}
}
@@ -1573,7 +1549,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) {
/// 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);
+ Record *Class = getClass(ClassName);
if (!Class)
throw "ERROR: Couldn't find the `" + ClassName + "' class!\n";
diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h
index d6f37eec749e..f3a5df23ec5c 100644
--- a/utils/TableGen/Record.h
+++ b/utils/TableGen/Record.h
@@ -16,7 +16,7 @@
#define RECORD_H
#include "llvm/Support/SourceMgr.h"
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
@@ -57,6 +57,7 @@ class VarListElementInit;
class Record;
class RecordVal;
struct MultiClass;
+class RecordKeeper;
//===----------------------------------------------------------------------===//
// Type Classes
@@ -810,7 +811,7 @@ public:
///
class UnOpInit : public OpInit {
public:
- enum UnaryOp { CAST, CAR, CDR, LNULL };
+ enum UnaryOp { CAST, HEAD, TAIL, EMPTY };
private:
UnaryOp Opc;
Init *LHS;
@@ -848,7 +849,7 @@ public:
///
class BinOpInit : public OpInit {
public:
- enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT, NAMECONCAT, EQ };
+ enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT, EQ };
private:
BinaryOp Opc;
Init *LHS, *RHS;
@@ -930,6 +931,8 @@ public:
// possible to fold.
Init *Fold(Record *CurRec, MultiClass *CurMultiClass);
+ virtual bool isComplete() const { return false; }
+
virtual Init *resolveReferences(Record &R, const RecordVal *RV);
virtual std::string getAsString() const;
@@ -1227,16 +1230,21 @@ class Record {
std::vector<std::string> TemplateArgs;
std::vector<RecordVal> Values;
std::vector<Record*> SuperClasses;
+
+ // Tracks Record instances. Not owned by Record.
+ RecordKeeper &TrackedRecords;
+
public:
- explicit Record(const std::string &N, SMLoc loc) :
- ID(LastID++), Name(N), Loc(loc) {}
+ // Constructs a record.
+ explicit Record(const std::string &N, SMLoc loc, RecordKeeper &records) :
+ ID(LastID++), Name(N), Loc(loc), TrackedRecords(records) {}
~Record() {}
-
+
static unsigned getNewUID() { return LastID++; }
-
-
+
+
unsigned getID() const { return ID; }
const std::string &getName() const { return Name; }
@@ -1315,6 +1323,10 @@ public:
/// possible references.
void resolveReferencesTo(const RecordVal *RV);
+ RecordKeeper &getRecords() const {
+ return TrackedRecords;
+ }
+
void dump() const;
//===--------------------------------------------------------------------===//
@@ -1350,9 +1362,9 @@ public:
///
std::vector<Record*> getValueAsListOfDefs(StringRef 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.
+ /// 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(StringRef FieldName) const;
@@ -1396,7 +1408,8 @@ struct MultiClass {
void dump() const;
- MultiClass(const std::string &Name, SMLoc Loc) : Rec(Name, Loc) {}
+ MultiClass(const std::string &Name, SMLoc Loc, RecordKeeper &Records) :
+ Rec(Name, Loc, Records) {}
};
class RecordKeeper {
@@ -1453,7 +1466,6 @@ public:
std::vector<Record*>
getAllDerivedDefinitions(const std::string &ClassName) const;
-
void dump() const;
};
@@ -1488,9 +1500,7 @@ public:
raw_ostream &operator<<(raw_ostream &OS, const RecordKeeper &RK);
-extern RecordKeeper Records;
-
-void PrintError(SMLoc ErrorLoc, const std::string &Msg);
+void PrintError(SMLoc ErrorLoc, const Twine &Msg);
} // End llvm namespace
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 6f06705243e9..96399a4d0525 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -25,7 +25,7 @@ using namespace llvm;
// runEnums - Print out enum values for all of the registers.
void RegisterInfoEmitter::runEnums(raw_ostream &OS) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");
@@ -63,7 +63,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS) {
void RegisterInfoEmitter::runHeader(raw_ostream &OS) {
EmitSourceFileHeader("Register Information Header Fragment", OS);
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
const std::string &TargetName = Target.getName();
std::string ClassName = TargetName + "GenRegisterInfo";
@@ -333,7 +333,7 @@ public:
// RegisterInfoEmitter::run - Main register file description emitter.
//
void RegisterInfoEmitter::run(raw_ostream &OS) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
EmitSourceFileHeader("Register Information Source Fragment", OS);
OS << "namespace llvm {\n\n";
@@ -777,17 +777,13 @@ void RegisterInfoEmitter::run(raw_ostream &OS) {
delete [] AliasesHashTable;
if (!RegisterAliases.empty())
- OS << "\n\n // Register Alias Sets...\n";
+ OS << "\n\n // Register Overlap Lists...\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.
+ // Emit an overlap list for all registers.
for (std::map<Record*, std::set<Record*>, LessRecord >::iterator
I = RegisterAliases.begin(), E = RegisterAliases.end(); I != E; ++I) {
- if (I->second.empty())
- continue;
- OS << " const unsigned " << I->first->getName() << "_AliasSet[] = { ";
+ OS << " const unsigned " << I->first->getName() << "_Overlaps[] = { "
+ << getQualifiedName(I->first) << ", ";
for (std::set<Record*>::iterator ASI = I->second.begin(),
E = I->second.end(); ASI != E; ++ASI)
OS << getQualifiedName(*ASI) << ", ";
@@ -849,11 +845,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) {
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
const CodeGenRegister &Reg = Regs[i];
OS << " { \"";
- OS << Reg.getName() << "\",\t";
- if (!RegisterAliases[Reg.TheDef].empty())
- OS << Reg.getName() << "_AliasSet,\t";
- else
- OS << "Empty_AliasSet,\t";
+ OS << Reg.getName() << "\",\t" << Reg.getName() << "_Overlaps,\t";
if (!RegisterSubRegs[Reg.TheDef].empty())
OS << Reg.getName() << "_SubRegsSet,\t";
else
diff --git a/utils/TableGen/StringMatcher.cpp b/utils/TableGen/StringMatcher.cpp
new file mode 100644
index 000000000000..6aedcbf458a8
--- /dev/null
+++ b/utils/TableGen/StringMatcher.cpp
@@ -0,0 +1,149 @@
+//===- StringMatcher.cpp - Generate a matcher for input strings -----------===//
+//
+// 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 StringMatcher class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringMatcher.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+using namespace llvm;
+
+/// FindFirstNonCommonLetter - Find the first character in the keys of the
+/// string pairs that is not shared across the whole set of strings. All
+/// strings are assumed to have the same length.
+static unsigned
+FindFirstNonCommonLetter(const std::vector<const
+ StringMatcher::StringPair*> &Matches) {
+ assert(!Matches.empty());
+ for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) {
+ // Check to see if letter i is the same across the set.
+ char Letter = Matches[0]->first[i];
+
+ for (unsigned str = 0, e = Matches.size(); str != e; ++str)
+ if (Matches[str]->first[i] != Letter)
+ return i;
+ }
+
+ return Matches[0]->first.size();
+}
+
+/// EmitStringMatcherForChar - Given a set of strings that are known to be the
+/// same length and whose characters leading up to CharNo are the same, emit
+/// code to verify that CharNo and later are the same.
+///
+/// \return - True if control can leave the emitted code fragment.
+bool StringMatcher::
+EmitStringMatcherForChar(const std::vector<const StringPair*> &Matches,
+ unsigned CharNo, unsigned IndentCount) const {
+ assert(!Matches.empty() && "Must have at least one string to match!");
+ std::string Indent(IndentCount*2+4, ' ');
+
+ // If we have verified that the entire string matches, we're done: output the
+ // matching code.
+ if (CharNo == Matches[0]->first.size()) {
+ assert(Matches.size() == 1 && "Had duplicate keys to match on");
+
+ // If the to-execute code has \n's in it, indent each subsequent line.
+ StringRef Code = Matches[0]->second;
+
+ std::pair<StringRef, StringRef> Split = Code.split('\n');
+ OS << Indent << Split.first << "\t // \"" << Matches[0]->first << "\"\n";
+
+ Code = Split.second;
+ while (!Code.empty()) {
+ Split = Code.split('\n');
+ OS << Indent << Split.first << "\n";
+ Code = Split.second;
+ }
+ return false;
+ }
+
+ // Bucket the matches by the character we are comparing.
+ std::map<char, std::vector<const StringPair*> > MatchesByLetter;
+
+ for (unsigned i = 0, e = Matches.size(); i != e; ++i)
+ MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]);
+
+
+ // If we have exactly one bucket to match, see how many characters are common
+ // across the whole set and match all of them at once.
+ if (MatchesByLetter.size() == 1) {
+ unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches);
+ unsigned NumChars = FirstNonCommonLetter-CharNo;
+
+ // Emit code to break out if the prefix doesn't match.
+ if (NumChars == 1) {
+ // Do the comparison with if (Str[1] != 'f')
+ // FIXME: Need to escape general characters.
+ OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '"
+ << Matches[0]->first[CharNo] << "')\n";
+ OS << Indent << " break;\n";
+ } else {
+ // Do the comparison with if (Str.substr(1, 3) != "foo").
+ // FIXME: Need to escape general strings.
+ OS << Indent << "if (" << StrVariableName << ".substr(" << CharNo << ", "
+ << NumChars << ") != \"";
+ OS << Matches[0]->first.substr(CharNo, NumChars) << "\")\n";
+ OS << Indent << " break;\n";
+ }
+
+ return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount);
+ }
+
+ // Otherwise, we have multiple possible things, emit a switch on the
+ // character.
+ OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n";
+ OS << Indent << "default: break;\n";
+
+ for (std::map<char, std::vector<const StringPair*> >::iterator LI =
+ MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) {
+ // TODO: escape hard stuff (like \n) if we ever care about it.
+ OS << Indent << "case '" << LI->first << "':\t // "
+ << LI->second.size() << " string";
+ if (LI->second.size() != 1) OS << 's';
+ OS << " to match.\n";
+ if (EmitStringMatcherForChar(LI->second, CharNo+1, IndentCount+1))
+ OS << Indent << " break;\n";
+ }
+
+ OS << Indent << "}\n";
+ return true;
+}
+
+
+/// Emit - Top level entry point.
+///
+void StringMatcher::Emit(unsigned Indent) const {
+ // If nothing to match, just fall through.
+ if (Matches.empty()) return;
+
+ // First level categorization: group strings by length.
+ std::map<unsigned, std::vector<const StringPair*> > MatchesByLength;
+
+ for (unsigned i = 0, e = Matches.size(); i != e; ++i)
+ MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]);
+
+ // Output a switch statement on length and categorize the elements within each
+ // bin.
+ OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n";
+ OS.indent(Indent*2+2) << "default: break;\n";
+
+ for (std::map<unsigned, std::vector<const StringPair*> >::iterator LI =
+ MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) {
+ OS.indent(Indent*2+2) << "case " << LI->first << ":\t // "
+ << LI->second.size()
+ << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n";
+ if (EmitStringMatcherForChar(LI->second, 0, Indent))
+ OS.indent(Indent*2+4) << "break;\n";
+ }
+
+ OS.indent(Indent*2+2) << "}\n";
+}
diff --git a/utils/TableGen/StringMatcher.h b/utils/TableGen/StringMatcher.h
new file mode 100644
index 000000000000..1dadc76200b0
--- /dev/null
+++ b/utils/TableGen/StringMatcher.h
@@ -0,0 +1,54 @@
+//===- StringMatcher.h - Generate a matcher for input strings ---*- C++ -*-===//
+//
+// 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 StringMatcher class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef STRINGMATCHER_H
+#define STRINGMATCHER_H
+
+#include <vector>
+#include <string>
+#include <utility>
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+ class raw_ostream;
+
+/// StringMatcher - Given a list of strings and code to execute when they match,
+/// output a simple switch tree to classify the input string.
+///
+/// If a match is found, the code in Vals[i].second is executed; control must
+/// not exit this code fragment. If nothing matches, execution falls through.
+///
+class StringMatcher {
+public:
+ typedef std::pair<std::string, std::string> StringPair;
+private:
+ StringRef StrVariableName;
+ const std::vector<StringPair> &Matches;
+ raw_ostream &OS;
+
+public:
+ StringMatcher(StringRef strVariableName,
+ const std::vector<StringPair> &matches, raw_ostream &os)
+ : StrVariableName(strVariableName), Matches(matches), OS(os) {}
+
+ void Emit(unsigned Indent = 0) const;
+
+
+private:
+ bool EmitStringMatcherForChar(const std::vector<const StringPair*> &Matches,
+ unsigned CharNo, unsigned IndentCount) const;
+};
+
+} // end llvm namespace.
+
+#endif
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index b04eaf88f73a..e35bdca97887 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -172,13 +172,10 @@ void SubtargetEmitter::CPUKeyValues(raw_ostream &OS) {
// CollectAllItinClasses - Gathers and enumerates all the itinerary classes.
// Returns itinerary class count.
//
-unsigned SubtargetEmitter::CollectAllItinClasses(raw_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());
-
+unsigned SubtargetEmitter::
+CollectAllItinClasses(raw_ostream &OS,
+ std::map<std::string, unsigned> &ItinClassesMap,
+ std::vector<Record*> &ItinClassList) {
// For each itinerary class
unsigned N = ItinClassList.size();
for (unsigned i = 0; i < N; i++) {
@@ -265,13 +262,32 @@ void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData,
}
}
+void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
+ Record *ItinData,
+ std::string &ItinString,
+ unsigned NOperandCycles) {
+ const std::vector<Record*> &BypassList =
+ ItinData->getValueAsListOfDefs("Bypasses");
+ unsigned N = BypassList.size();
+ unsigned i = 0;
+ for (; i < N;) {
+ ItinString += Name + "Bypass::" + BypassList[i]->getName();
+ if (++i < NOperandCycles) ItinString += ", ";
+ }
+ for (; i < NOperandCycles;) {
+ ItinString += " 0";
+ if (++i < NOperandCycles) ItinString += ", ";
+ }
+}
+
//
// EmitStageAndOperandCycleData - Generate unique itinerary stages and
// operand cycle tables. Record itineraries for processors.
//
void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
unsigned NItinClasses,
- std::map<std::string, unsigned> &ItinClassesMap,
+ std::map<std::string, unsigned> &ItinClassesMap,
+ std::vector<Record*> &ItinClassList,
std::vector<std::vector<InstrItinerary> > &ProcList) {
// Gather processor iteraries
std::vector<Record*> ProcItinList =
@@ -298,6 +314,19 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
<< " = 1 << " << j << ";\n";
OS << "}\n";
+
+ std::vector<Record*> BPs = Proc->getValueAsListOfDefs("BP");
+ if (BPs.size()) {
+ OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name
+ << "\"\n" << "namespace " << Name << "Bypass {\n";
+
+ OS << " const unsigned NoBypass = 0;\n";
+ for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
+ OS << " const unsigned " << BPs[j]->getName()
+ << " = 1 << " << j << ";\n";
+
+ OS << "}\n";
+ }
}
// Begin stages table
@@ -307,10 +336,14 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
// Begin operand cycle table
std::string OperandCycleTable = "static const unsigned OperandCycles[] = {\n";
OperandCycleTable += " 0, // No itinerary\n";
+
+ // Begin pipeline bypass table
+ std::string BypassTable = "static const unsigned ForwardingPathes[] = {\n";
+ BypassTable += " 0, // No itinerary\n";
unsigned StageCount = 1, OperandCycleCount = 1;
unsigned ItinStageEnum = 1, ItinOperandCycleEnum = 1;
- std::map<std::string, unsigned> ItinStageMap, ItinOperandCycleMap;
+ std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
// Next record
Record *Proc = ProcItinList[i];
@@ -344,6 +377,10 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
NOperandCycles);
+ std::string ItinBypassString;
+ FormItineraryBypassString(Name, ItinData, ItinBypassString,
+ NOperandCycles);
+
// Check to see if stage already exists and create if it doesn't
unsigned FindStage = 0;
if (NStages > 0) {
@@ -361,27 +398,35 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
// Check to see if operand cycle already exists and create if it doesn't
unsigned FindOperandCycle = 0;
if (NOperandCycles > 0) {
- FindOperandCycle = ItinOperandCycleMap[ItinOperandCycleString];
+ std::string ItinOperandString = ItinOperandCycleString+ItinBypassString;
+ FindOperandCycle = ItinOperandMap[ItinOperandString];
if (FindOperandCycle == 0) {
// Emit as cycle, // index
OperandCycleTable += ItinOperandCycleString + ", // " +
itostr(ItinOperandCycleEnum) + "\n";
// Record Itin class number.
- ItinOperandCycleMap[ItinOperandCycleString] =
+ ItinOperandMap[ItinOperandCycleString] =
FindOperandCycle = OperandCycleCount;
+
+ // Emit as bypass, // index
+ BypassTable += ItinBypassString + ", // " +
+ itostr(ItinOperandCycleEnum) + "\n";
+
OperandCycleCount += NOperandCycles;
ItinOperandCycleEnum++;
}
}
- // Set up itinerary as location and location + stage count
- InstrItinerary Intinerary = { FindStage, FindStage + NStages,
- FindOperandCycle, FindOperandCycle + NOperandCycles};
-
// Locate where to inject into processor itinerary table
const std::string &Name = ItinData->getValueAsDef("TheClass")->getName();
unsigned Find = ItinClassesMap[Name];
+ // Set up itinerary as location and location + stage count
+ unsigned NumUOps = ItinClassList[Find]->getValueAsInt("NumMicroOps");
+ InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages,
+ FindOperandCycle,
+ FindOperandCycle + NOperandCycles};
+
// Inject - empty slots will be 0, 0
ItinList[Find] = Intinerary;
}
@@ -389,7 +434,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
// Add process itinerary to list
ProcList.push_back(ItinList);
}
-
+
// Closing stage
StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n";
StageTable += "};\n";
@@ -398,9 +443,13 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
OperandCycleTable += " 0 // End itinerary\n";
OperandCycleTable += "};\n";
+ BypassTable += " 0 // End itinerary\n";
+ BypassTable += "};\n";
+
// Emit tables.
OS << StageTable;
OS << OperandCycleTable;
+ OS << BypassTable;
// Emit size of tables
OS<<"\nenum {\n";
@@ -443,9 +492,11 @@ void SubtargetEmitter::EmitProcessorData(raw_ostream &OS,
// Emit in the form of
// { firstStage, lastStage, firstCycle, lastCycle } // index
if (Intinerary.FirstStage == 0) {
- OS << " { 0, 0, 0, 0 }";
+ OS << " { 1, 0, 0, 0, 0 }";
} else {
- OS << " { " << Intinerary.FirstStage << ", " <<
+ OS << " { " <<
+ Intinerary.NumMicroOps << ", " <<
+ Intinerary.FirstStage << ", " <<
Intinerary.LastStage << ", " <<
Intinerary.FirstOperandCycle << ", " <<
Intinerary.LastOperandCycle << " }";
@@ -455,7 +506,7 @@ void SubtargetEmitter::EmitProcessorData(raw_ostream &OS,
}
// End processor itinerary table
- OS << " { ~0U, ~0U, ~0U, ~0U } // end marker\n";
+ OS << " { 1, ~0U, ~0U, ~0U, ~0U } // end marker\n";
OS << "};\n";
}
}
@@ -511,16 +562,22 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
//
void SubtargetEmitter::EmitData(raw_ostream &OS) {
std::map<std::string, unsigned> ItinClassesMap;
- std::vector<std::vector<InstrItinerary> > ProcList;
+ // Gather and sort all itinerary classes
+ std::vector<Record*> ItinClassList =
+ Records.getAllDerivedDefinitions("InstrItinClass");
+ std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord());
// Enumerate all the itinerary classes
- unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap);
+ unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap,
+ ItinClassList);
// Make sure the rest is worth the effort
HasItineraries = NItinClasses != 1; // Ignore NoItinerary.
if (HasItineraries) {
+ std::vector<std::vector<InstrItinerary> > ProcList;
// Emit the stage data
- EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap, ProcList);
+ EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap,
+ ItinClassList, ProcList);
// Emit the processor itinerary data
EmitProcessorData(OS, ProcList);
// Emit the processor lookup data
@@ -569,7 +626,8 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
OS << "\n"
<< " InstrItinerary *Itinerary = (InstrItinerary *)"
<< "Features.getInfo(ProcItinKV, ProcItinKVSize);\n"
- << " InstrItins = InstrItineraryData(Stages, OperandCycles, Itinerary);\n";
+ << " InstrItins = InstrItineraryData(Stages, OperandCycles, "
+ << "ForwardingPathes, Itinerary);\n";
}
OS << " return Features.getCPU();\n"
@@ -580,7 +638,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
// SubtargetEmitter::run - Main subtarget enumeration emitter.
//
void SubtargetEmitter::run(raw_ostream &OS) {
- Target = CodeGenTarget().getName();
+ Target = CodeGenTarget(Records).getName();
EmitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h
index f43a4431d61e..3abec3b24091 100644
--- a/utils/TableGen/SubtargetEmitter.h
+++ b/utils/TableGen/SubtargetEmitter.h
@@ -33,14 +33,19 @@ class SubtargetEmitter : public TableGenBackend {
void FeatureKeyValues(raw_ostream &OS);
void CPUKeyValues(raw_ostream &OS);
unsigned CollectAllItinClasses(raw_ostream &OS,
- std::map<std::string, unsigned> &ItinClassesMap);
+ std::map<std::string,unsigned> &ItinClassesMap,
+ std::vector<Record*> &ItinClassList);
void FormItineraryStageString(const std::string &Names,
Record *ItinData, std::string &ItinString,
unsigned &NStages);
void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
unsigned &NOperandCycles);
+ void FormItineraryBypassString(const std::string &Names,
+ Record *ItinData,
+ std::string &ItinString, unsigned NOperandCycles);
void EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses,
std::map<std::string, unsigned> &ItinClassesMap,
+ std::vector<Record*> &ItinClassList,
std::vector<std::vector<InstrItinerary> > &ProcList);
void EmitProcessorData(raw_ostream &OS,
std::vector<std::vector<InstrItinerary> > &ProcList);
diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp
index 2c7becc71824..82d2b6491aac 100644
--- a/utils/TableGen/TGLexer.cpp
+++ b/utils/TableGen/TGLexer.cpp
@@ -15,6 +15,8 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Config/config.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
#include <cctype>
#include <cstdio>
#include <cstdlib>
@@ -36,17 +38,17 @@ SMLoc TGLexer::getLoc() const {
/// 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) {
+tgtok::TokKind TGLexer::ReturnError(const char *Loc, const Twine &Msg) {
PrintError(Loc, Msg);
return tgtok::Error;
}
-void TGLexer::PrintError(const char *Loc, const std::string &Msg) const {
+void TGLexer::PrintError(const char *Loc, const Twine &Msg) const {
SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), Msg, "error");
}
-void TGLexer::PrintError(SMLoc Loc, const std::string &Msg) const {
+void TGLexer::PrintError(SMLoc Loc, const Twine &Msg) const {
SrcMgr.PrintMessage(Loc, Msg, "error");
}
@@ -95,7 +97,7 @@ tgtok::TokKind TGLexer::LexToken() {
switch (CurChar) {
default:
- // Handle letters: [a-zA-Z_]
+ // Handle letters: [a-zA-Z_#]
if (isalpha(CurChar) || CurChar == '_' || CurChar == '#')
return LexIdentifier();
@@ -214,23 +216,13 @@ tgtok::TokKind TGLexer::LexVarName() {
tgtok::TokKind TGLexer::LexIdentifier() {
- // The first letter is [a-zA-Z_].
+ // 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;
- }
- }
+ // Match the rest of the identifier regex: [0-9a-zA-Z_#]*
+ while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_' ||
+ *CurPtr == '#')
+ ++CurPtr;
// Check to see if this identifier is a keyword.
@@ -421,30 +413,30 @@ tgtok::TokKind TGLexer::LexBracket() {
/// LexExclaim - Lex '!' and '![a-zA-Z]+'.
tgtok::TokKind TGLexer::LexExclaim() {
if (!isalpha(*CurPtr))
- return ReturnError(CurPtr-1, "Invalid \"!operator\"");
+ 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 == 2 && !memcmp(Start, "eq", 2)) return tgtok::XEq;
- 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");
+ tgtok::TokKind Kind =
+ StringSwitch<tgtok::TokKind>(StringRef(Start, CurPtr - Start))
+ .Case("eq", tgtok::XEq)
+ .Case("if", tgtok::XIf)
+ .Case("head", tgtok::XHead)
+ .Case("tail", tgtok::XTail)
+ .Case("con", tgtok::XConcat)
+ .Case("shl", tgtok::XSHL)
+ .Case("sra", tgtok::XSRA)
+ .Case("srl", tgtok::XSRL)
+ .Case("cast", tgtok::XCast)
+ .Case("empty", tgtok::XEmpty)
+ .Case("subst", tgtok::XSubst)
+ .Case("foreach", tgtok::XForEach)
+ .Case("strconcat", tgtok::XStrConcat)
+ .Default(tgtok::Error);
+
+ return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator");
}
diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h
index 835f351d3d0d..55a6c5d9b52e 100644
--- a/utils/TableGen/TGLexer.h
+++ b/utils/TableGen/TGLexer.h
@@ -14,7 +14,7 @@
#ifndef TGLEXER_H
#define TGLEXER_H
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
#include <vector>
#include <string>
#include <cassert>
@@ -23,7 +23,8 @@ namespace llvm {
class MemoryBuffer;
class SourceMgr;
class SMLoc;
-
+class Twine;
+
namespace tgtok {
enum TokKind {
// Markers
@@ -44,8 +45,8 @@ namespace tgtok {
MultiClass, String,
// !keywords.
- XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst,
- XForEach, XCar, XCdr, XNull, XIf, XEq,
+ XConcat, XSRA, XSRL, XSHL, XStrConcat, XCast, XSubst,
+ XForEach, XHead, XTail, XEmpty, XIf, XEq,
// Integer value.
IntVal,
@@ -95,14 +96,14 @@ public:
SMLoc getLoc() const;
- void PrintError(const char *Loc, const std::string &Msg) const;
- void PrintError(SMLoc Loc, const std::string &Msg) const;
+ void PrintError(const char *Loc, const Twine &Msg) const;
+ void PrintError(SMLoc Loc, const Twine &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);
+ tgtok::TokKind ReturnError(const char *Loc, const Twine &Msg);
int getNextChar();
void SkipBCPLComment();
diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp
index f81aabe79b03..f6041be95e16 100644
--- a/utils/TableGen/TGParser.cpp
+++ b/utils/TableGen/TGParser.cpp
@@ -16,6 +16,8 @@
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
#include <sstream>
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/CommandLine.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
@@ -294,20 +296,23 @@ static bool isObjectStart(tgtok::TokKind K) {
K == tgtok::Defm || K == tgtok::Let || K == tgtok::MultiClass;
}
+static std::string GetNewAnonymousName() {
+ static unsigned AnonCounter = 0;
+ return "anonymous."+utostr(AnonCounter++);
+}
+
/// 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;
- }
+ if (Lex.getCode() != tgtok::Id)
+ return GetNewAnonymousName();
- static unsigned AnonCounter = 0;
- return "anonymous."+utostr(AnonCounter++);
+ std::string Ret = Lex.getCurStrVal();
+ Lex.Lex();
+ return Ret;
}
@@ -678,9 +683,9 @@ Init *TGParser::ParseOperation(Record *CurRec) {
TokError("unknown operation");
return 0;
break;
- case tgtok::XCar:
- case tgtok::XCdr:
- case tgtok::XNull:
+ case tgtok::XHead:
+ case tgtok::XTail:
+ case tgtok::XEmpty:
case tgtok::XCast: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code;
RecTy *Type = 0;
@@ -699,17 +704,17 @@ Init *TGParser::ParseOperation(Record *CurRec) {
}
break;
- case tgtok::XCar:
+ case tgtok::XHead:
Lex.Lex(); // eat the operation
- Code = UnOpInit::CAR;
+ Code = UnOpInit::HEAD;
break;
- case tgtok::XCdr:
+ case tgtok::XTail:
Lex.Lex(); // eat the operation
- Code = UnOpInit::CDR;
+ Code = UnOpInit::TAIL;
break;
- case tgtok::XNull:
+ case tgtok::XEmpty:
Lex.Lex(); // eat the operation
- Code = UnOpInit::LNULL;
+ Code = UnOpInit::EMPTY;
Type = new IntRecTy;
break;
}
@@ -722,9 +727,9 @@ Init *TGParser::ParseOperation(Record *CurRec) {
Init *LHS = ParseValue(CurRec);
if (LHS == 0) return 0;
- if (Code == UnOpInit::CAR
- || Code == UnOpInit::CDR
- || Code == UnOpInit::LNULL) {
+ if (Code == UnOpInit::HEAD
+ || Code == UnOpInit::TAIL
+ || Code == UnOpInit::EMPTY) {
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS);
@@ -741,8 +746,8 @@ Init *TGParser::ParseOperation(Record *CurRec) {
}
}
- if (Code == UnOpInit::CAR
- || Code == UnOpInit::CDR) {
+ if (Code == UnOpInit::HEAD
+ || Code == UnOpInit::TAIL) {
if (LHSl == 0 && LHSt == 0) {
TokError("expected list type argumnet in unary operator");
return 0;
@@ -759,7 +764,7 @@ Init *TGParser::ParseOperation(Record *CurRec) {
TokError("untyped list element in unary operator");
return 0;
}
- if (Code == UnOpInit::CAR) {
+ if (Code == UnOpInit::HEAD) {
Type = Itemt->getType();
} else {
Type = new ListRecTy(Itemt->getType());
@@ -771,7 +776,7 @@ Init *TGParser::ParseOperation(Record *CurRec) {
TokError("expected list type argumnet in unary operator");
return 0;
}
- if (Code == UnOpInit::CAR) {
+ if (Code == UnOpInit::HEAD) {
Type = LType->getElementType();
} else {
Type = LType;
@@ -793,81 +798,68 @@ Init *TGParser::ParseOperation(Record *CurRec) {
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XEq:
- case tgtok::XStrConcat:
- case tgtok::XNameConcat: { // Value ::= !binop '(' Value ',' Value ')'
+ case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')'
+ tgtok::TokKind OpTok = Lex.getCode();
+ SMLoc OpLoc = Lex.getLoc();
+ Lex.Lex(); // eat the operation
+
BinOpInit::BinaryOp Code;
RecTy *Type = 0;
-
- switch (Lex.getCode()) {
+ switch (OpTok) {
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::XEq:
- Lex.Lex(); // eat the operation
- Code = BinOpInit::EQ;
- Type = new IntRecTy();
- break;
+ case tgtok::XConcat: Code = BinOpInit::CONCAT; Type = new DagRecTy(); break;
+ case tgtok::XSRA: Code = BinOpInit::SRA; Type = new IntRecTy(); break;
+ case tgtok::XSRL: Code = BinOpInit::SRL; Type = new IntRecTy(); break;
+ case tgtok::XSHL: Code = BinOpInit::SHL; Type = new IntRecTy(); break;
+ case tgtok::XEq: Code = BinOpInit::EQ; Type = new BitRecTy(); 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;
+ SmallVector<Init*, 2> InitList;
- if (Lex.getCode() != tgtok::comma) {
- TokError("expected ',' in binary operator");
- return 0;
- }
- Lex.Lex(); // eat the ','
+ InitList.push_back(ParseValue(CurRec));
+ if (InitList.back() == 0) return 0;
- Init *RHS = ParseValue(CurRec);
- if (RHS == 0) return 0;
+ while (Lex.getCode() == tgtok::comma) {
+ Lex.Lex(); // eat the ','
+
+ InitList.push_back(ParseValue(CurRec));
+ if (InitList.back() == 0) return 0;
+ }
if (Lex.getCode() != tgtok::r_paren) {
- TokError("expected ')' in binary operator");
+ TokError("expected ')' in operator");
return 0;
}
Lex.Lex(); // eat the ')'
- return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass);
+
+ // We allow multiple operands to associative operators like !strconcat as
+ // shorthand for nesting them.
+ if (Code == BinOpInit::STRCONCAT) {
+ while (InitList.size() > 2) {
+ Init *RHS = InitList.pop_back_val();
+ RHS = (new BinOpInit(Code, InitList.back(), RHS, Type))
+ ->Fold(CurRec, CurMultiClass);
+ InitList.back() = RHS;
+ }
+ }
+
+ if (InitList.size() == 2)
+ return (new BinOpInit(Code, InitList[0], InitList[1], Type))
+ ->Fold(CurRec, CurMultiClass);
+
+ Error(OpLoc, "expected two operands to operator");
+ return 0;
}
case tgtok::XIf:
@@ -876,7 +868,6 @@ Init *TGParser::ParseOperation(Record *CurRec) {
TernOpInit::TernaryOp Code;
RecTy *Type = 0;
-
tgtok::TokKind LexCode = Lex.getCode();
Lex.Lex(); // eat the operation
switch (LexCode) {
@@ -927,16 +918,45 @@ Init *TGParser::ParseOperation(Record *CurRec) {
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) {
+ // FIXME: The `!if' operator doesn't handle non-TypedInit well at
+ // all. This can be made much more robust.
+ TypedInit *MHSt = dynamic_cast<TypedInit*>(MHS);
+ TypedInit *RHSt = dynamic_cast<TypedInit*>(RHS);
+
+ RecTy *MHSTy = 0;
+ RecTy *RHSTy = 0;
+
+ if (MHSt == 0 && RHSt == 0) {
+ BitsInit *MHSbits = dynamic_cast<BitsInit*>(MHS);
+ BitsInit *RHSbits = dynamic_cast<BitsInit*>(RHS);
+
+ if (MHSbits && RHSbits &&
+ MHSbits->getNumBits() == RHSbits->getNumBits()) {
+ Type = new BitRecTy();
+ break;
+ } else {
+ BitInit *MHSbit = dynamic_cast<BitInit*>(MHS);
+ BitInit *RHSbit = dynamic_cast<BitInit*>(RHS);
+
+ if (MHSbit && RHSbit) {
+ Type = new BitRecTy();
+ break;
+ }
+ }
+ } else if (MHSt != 0 && RHSt != 0) {
+ MHSTy = MHSt->getType();
+ RHSTy = RHSt->getType();
+ }
+
+ if (!MHSTy || !RHSTy) {
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();
+
+ if (MHSTy->typeIsConvertibleTo(RHSTy)) {
+ Type = RHSTy;
+ } else if (RHSTy->typeIsConvertibleTo(MHSTy)) {
+ Type = MHSTy;
} else {
TokError("inconsistent types for !if");
return 0;
@@ -1037,8 +1057,13 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) {
break;
}
case tgtok::CodeFragment:
- R = new CodeInit(Lex.getCurStrVal()); Lex.Lex(); break;
- case tgtok::question: R = new UnsetInit(); Lex.Lex(); break;
+ R = new CodeInit(Lex.getCurStrVal());
+ Lex.Lex();
+ break;
+ case tgtok::question:
+ R = new UnsetInit();
+ Lex.Lex();
+ break;
case tgtok::Id: {
SMLoc NameLoc = Lex.getLoc();
std::string Name = Lex.getCurStrVal();
@@ -1071,7 +1096,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) {
// Create the new record, set it as CurRec temporarily.
static unsigned AnonCounter = 0;
- Record *NewRec = new Record("anonymous.val."+utostr(AnonCounter++),NameLoc);
+ Record *NewRec = new Record("anonymous.val."+utostr(AnonCounter++),
+ NameLoc,
+ Records);
SubClassReference SCRef;
SCRef.RefLoc = NameLoc;
SCRef.Rec = Class;
@@ -1212,21 +1239,13 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) {
}
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
Lex.Lex(); // eat the '('
- if (Lex.getCode() != tgtok::Id
- && Lex.getCode() != tgtok::XCast
- && Lex.getCode() != tgtok::XNameConcat) {
+ if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast) {
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;
- }
+ Init *Operator = ParseValue(CurRec);
+ if (Operator == 0) return 0;
// If the operator name is present, parse it.
std::string OperatorName;
@@ -1252,25 +1271,22 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) {
Lex.Lex(); // eat the ')'
return new DagInit(Operator, OperatorName, DagArgs);
- break;
}
- case tgtok::XCar:
- case tgtok::XCdr:
- case tgtok::XNull:
+ case tgtok::XHead:
+ case tgtok::XTail:
+ case tgtok::XEmpty:
case tgtok::XCast: // Value ::= !unop '(' Value ')'
case tgtok::XConcat:
case tgtok::XSRA:
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XEq:
- case tgtok::XStrConcat:
- case tgtok::XNameConcat: // Value ::= !binop '(' Value ',' Value ')'
+ case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf:
case tgtok::XForEach:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
return ParseOperation(CurRec);
- break;
}
}
@@ -1646,7 +1662,7 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
Lex.Lex(); // Eat the 'def' token.
// Parse ObjectName and make a record for it.
- Record *CurRec = new Record(ParseObjectName(), DefLoc);
+ Record *CurRec = new Record(ParseObjectName(), DefLoc, Records);
if (!CurMultiClass) {
// Top-level def definition.
@@ -1713,7 +1729,7 @@ bool TGParser::ParseClass() {
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());
+ CurRec = new Record(Lex.getCurStrVal(), Lex.getLoc(), Records);
Records.addClass(CurRec);
}
Lex.Lex(); // eat the name.
@@ -1830,7 +1846,8 @@ bool TGParser::ParseMultiClass() {
if (MultiClasses.count(Name))
return TokError("multiclass '" + Name + "' already defined");
- CurMultiClass = MultiClasses[Name] = new MultiClass(Name, Lex.getLoc());
+ CurMultiClass = MultiClasses[Name] = new MultiClass(Name,
+ Lex.getLoc(), Records);
Lex.Lex(); // Eat the identifier.
// If there are template args, parse them.
@@ -1899,12 +1916,15 @@ bool TGParser::ParseMultiClass() {
///
bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
assert(Lex.getCode() == tgtok::Defm && "Unexpected token!");
- if (Lex.Lex() != tgtok::Id) // eat the defm.
- return TokError("expected identifier after defm");
+
+ std::string DefmPrefix;
+ if (Lex.Lex() == tgtok::Id) { // eat the defm.
+ DefmPrefix = Lex.getCurStrVal();
+ Lex.Lex(); // Eat the defm prefix.
+ }
SMLoc DefmPrefixLoc = Lex.getLoc();
- std::string DefmPrefix = Lex.getCurStrVal();
- if (Lex.Lex() != tgtok::colon)
+ if (Lex.getCode() != tgtok::colon)
return TokError("expected ':' after defm identifier");
// Keep track of the new generated record definitions.
@@ -1939,17 +1959,24 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
for (unsigned i = 0, e = MC->DefPrototypes.size(); i != e; ++i) {
Record *DefProto = MC->DefPrototypes[i];
- // Add in the defm name
+ // Add in the defm name. If the defm prefix is empty, give each
+ // instantiated def a unique name. Otherwise, if "#NAME#" exists in the
+ // name, substitute the prefix for #NAME#. Otherwise, use the defm name
+ // as a prefix.
std::string DefName = DefProto->getName();
- std::string::size_type idx = DefName.find("#NAME#");
- if (idx != std::string::npos) {
- DefName.replace(idx, 6, DefmPrefix);
+ if (DefmPrefix.empty()) {
+ DefName = GetNewAnonymousName();
} else {
- // Add the suffix to the defm name to get the new name.
- DefName = DefmPrefix + DefName;
+ 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);
+ Record *CurRec = new Record(DefName, DefmPrefixLoc, Records);
SubClassReference Ref;
Ref.RefLoc = DefmPrefixLoc;
@@ -2091,7 +2118,8 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
/// Object ::= LETCommand Object
bool TGParser::ParseObject(MultiClass *MC) {
switch (Lex.getCode()) {
- default: assert(0 && "This is not an object");
+ default:
+ return TokError("Expected class, def, defm, multiclass or let definition");
case tgtok::Let: return ParseTopLevelLet(MC);
case tgtok::Def: return ParseDef(MC);
case tgtok::Defm: return ParseDefm(MC);
diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h
index 0aee931423a6..9cdf68ff9749 100644
--- a/utils/TableGen/TGParser.h
+++ b/utils/TableGen/TGParser.h
@@ -15,12 +15,14 @@
#define TGPARSER_H
#include "TGLexer.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/SourceMgr.h"
#include <map>
namespace llvm {
class Record;
class RecordVal;
+ class RecordKeeper;
struct RecTy;
struct Init;
struct MultiClass;
@@ -46,18 +48,22 @@ class TGParser {
/// CurMultiClass - If we are parsing a 'multiclass' definition, this is the
/// current value.
MultiClass *CurMultiClass;
+
+ // Record tracker
+ RecordKeeper &Records;
public:
- TGParser(SourceMgr &SrcMgr) : Lex(SrcMgr), CurMultiClass(0) {}
+ TGParser(SourceMgr &SrcMgr, RecordKeeper &records) :
+ Lex(SrcMgr), CurMultiClass(0), Records(records) {}
/// ParseFile - Main entrypoint for parsing a tblgen file. These parser
/// routines return true on error, or false on success.
bool ParseFile();
- bool Error(SMLoc L, const std::string &Msg) const {
+ bool Error(SMLoc L, const Twine &Msg) const {
Lex.PrintError(L, Msg);
return true;
}
- bool TokError(const std::string &Msg) const {
+ bool TokError(const Twine &Msg) const {
return Error(Lex.getLoc(), Msg);
}
private: // Semantic analysis methods.
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 5e3e2829b87f..3b7dc0193b28 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -21,6 +21,7 @@
#include "ClangASTNodesEmitter.h"
#include "ClangAttrEmitter.h"
#include "ClangDiagnosticsEmitter.h"
+#include "ClangSACheckersEmitter.h"
#include "CodeEmitterGen.h"
#include "DAGISelEmitter.h"
#include "DisassemblerEmitter.h"
@@ -37,11 +38,13 @@
#include "ARMDecoderEmitter.h"
#include "SubtargetEmitter.h"
#include "TGParser.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstdio>
using namespace llvm;
@@ -59,10 +62,12 @@ enum ActionType {
GenClangAttrList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
+ GenClangAttrSpellingList,
GenClangDiagsDefs,
GenClangDiagGroups,
GenClangDeclNodes,
GenClangStmtNodes,
+ GenClangSACheckers,
GenDAGISel,
GenFastISel,
GenOptParserDefs, GenOptParserImpl,
@@ -73,6 +78,7 @@ enum ActionType {
GenEDInfo,
GenArmNeon,
GenArmNeonSema,
+ GenArmNeonTest,
PrintEnums
};
@@ -127,14 +133,18 @@ namespace {
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
"Generate clang PCH attribute writer"),
+ clEnumValN(GenClangAttrSpellingList, "gen-clang-attr-spelling-list",
+ "Generate a clang attribute spelling list"),
clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
"Generate Clang diagnostics definitions"),
clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
"Generate Clang diagnostic groups"),
clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes",
- "Generate Clang AST statement nodes"),
+ "Generate Clang AST declaration nodes"),
clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes",
"Generate Clang AST statement nodes"),
+ clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
+ "Generate Clang Static Analyzer checkers"),
clEnumValN(GenLLVMCConf, "gen-llvmc",
"Generate LLVMC configuration library"),
clEnumValN(GenEDInfo, "gen-enhanced-disassembly-info",
@@ -143,6 +153,8 @@ namespace {
"Generate arm_neon.h for clang"),
clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
"Generate ARM NEON sema support for clang"),
+ clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
+ "Generate ARM NEON tests for clang"),
clEnumValN(PrintEnums, "print-enums",
"Print enum values for a class"),
clEnumValEnd));
@@ -169,12 +181,9 @@ namespace {
}
-// FIXME: Eliminate globals from tblgen.
-RecordKeeper llvm::Records;
-
static SourceMgr SrcMgr;
-void llvm::PrintError(SMLoc ErrorLoc, const std::string &Msg) {
+void llvm::PrintError(SMLoc ErrorLoc, const Twine &Msg) {
SrcMgr.PrintMessage(ErrorLoc, Msg, "error");
}
@@ -184,14 +193,15 @@ void llvm::PrintError(SMLoc ErrorLoc, const std::string &Msg) {
/// file.
static bool ParseFile(const std::string &Filename,
const std::vector<std::string> &IncludeDirs,
- SourceMgr &SrcMgr) {
- std::string ErrorStr;
- MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr);
- if (F == 0) {
+ SourceMgr &SrcMgr,
+ RecordKeeper &Records) {
+ OwningPtr<MemoryBuffer> File;
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), File)) {
errs() << "Could not open input file '" << Filename << "': "
- << ErrorStr <<"\n";
+ << ec.message() <<"\n";
return true;
}
+ MemoryBuffer *F = File.take();
// Tell SrcMgr about this buffer, which is what TGParser will pick up.
SrcMgr.AddNewSourceBuffer(F, SMLoc());
@@ -200,19 +210,21 @@ static bool ParseFile(const std::string &Filename,
// it later.
SrcMgr.setIncludeDirs(IncludeDirs);
- TGParser Parser(SrcMgr);
+ TGParser Parser(SrcMgr, Records);
return Parser.ParseFile();
}
int main(int argc, char **argv) {
+ RecordKeeper Records;
+
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
// Parse the input file.
- if (ParseFile(InputFilename, IncludeDirs, SrcMgr))
+ if (ParseFile(InputFilename, IncludeDirs, SrcMgr, Records))
return 1;
std::string Error;
@@ -274,6 +286,9 @@ int main(int argc, char **argv) {
case GenClangAttrPCHWrite:
ClangAttrPCHWriteEmitter(Records).run(Out.os());
break;
+ case GenClangAttrSpellingList:
+ ClangAttrSpellingListEmitter(Records).run(Out.os());
+ break;
case GenClangDiagsDefs:
ClangDiagsDefsEmitter(Records, ClangComponent).run(Out.os());
break;
@@ -287,6 +302,9 @@ int main(int argc, char **argv) {
case GenClangStmtNodes:
ClangASTNodesEmitter(Records, "Stmt", "").run(Out.os());
break;
+ case GenClangSACheckers:
+ ClangSACheckersEmitter(Records).run(Out.os());
+ break;
case GenDisassembler:
DisassemblerEmitter(Records).run(Out.os());
break;
@@ -323,6 +341,9 @@ int main(int argc, char **argv) {
case GenArmNeonSema:
NeonEmitter(Records).runHeader(Out.os());
break;
+ case GenArmNeonTest:
+ NeonEmitter(Records).runTests(Out.os());
+ break;
case PrintEnums:
{
std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index 2176224523a3..94797f55f713 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -161,7 +161,7 @@ void DisassemblerTables::emitOneID(raw_ostream &o,
/// @param i - The indentation level for that output stream.
static void emitEmptyTable(raw_ostream &o, uint32_t &i)
{
- o.indent(i * 2) << "static InstrUID modRMEmptyTable[1] = { 0 };" << "\n";
+ o.indent(i * 2) << "static const InstrUID modRMEmptyTable[1] = { 0 };\n";
o << "\n";
}
@@ -275,7 +275,7 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
return;
}
- o1.indent(i1) << "static InstrUID modRMTable" << thisTableNumber;
+ o1.indent(i1) << "static const InstrUID modRMTable" << thisTableNumber;
switch (dt) {
default:
@@ -365,7 +365,7 @@ void DisassemblerTables::emitContextDecision(
uint32_t &i2,
ContextDecision &decision,
const char* name) const {
- o2.indent(i2) << "struct ContextDecision " << name << " = {" << "\n";
+ o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
i2++;
o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
i2++;
@@ -392,10 +392,8 @@ void DisassemblerTables::emitContextDecision(
void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
const {
- o.indent(i * 2) << "struct InstructionSpecifier ";
- o << INSTRUCTIONS_STR << "[";
- o << InstructionSpecifiers.size();
- o << "] = {" << "\n";
+ o.indent(i * 2) << "static const struct InstructionSpecifier ";
+ o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
i++;
@@ -456,8 +454,8 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
uint16_t index;
- o.indent(i * 2) << "InstructionContext ";
- o << CONTEXTS_STR << "[256] = {" << "\n";
+ o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
+ "[256] = {\n";
i++;
for (index = 0; index < 256; ++index) {
diff --git a/utils/TableGen/X86ModRMFilters.h b/utils/TableGen/X86ModRMFilters.h
index 45cb07a3d393..199040bad840 100644
--- a/utils/TableGen/X86ModRMFilters.h
+++ b/utils/TableGen/X86ModRMFilters.h
@@ -18,7 +18,7 @@
#ifndef X86MODRMFILTERS_H
#define X86MODRMFILTERS_H
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
namespace llvm {
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index 4dba85b16681..ccd3efd980a2 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -51,10 +51,11 @@ namespace X86Local {
MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27,
MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31,
MRMInitReg = 32,
-
#define MAP(from, to) MRM_##from = to,
MRM_MAPPING
#undef MAP
+ RawFrmImm8 = 43,
+ RawFrmImm16 = 44,
lastMRM
};
@@ -113,7 +114,6 @@ namespace X86Local {
EXTENSION_TABLE(72) \
EXTENSION_TABLE(73) \
EXTENSION_TABLE(ae) \
- EXTENSION_TABLE(b9) \
EXTENSION_TABLE(ba) \
EXTENSION_TABLE(c7)
@@ -219,7 +219,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
Name = Rec->getName();
AsmString = Rec->getValueAsString("AsmString");
- Operands = &insn.OperandList;
+ Operands = &insn.Operands.OperandList;
IsSSE = HasOpSizePrefix && (Name.find("16") == Name.npos);
HasFROperands = false;
@@ -311,7 +311,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
return FILTER_STRONG;
// Special cases.
-
+
if (Name.find("PCMPISTRI") != Name.npos && Name != "PCMPISTRI")
return FILTER_WEAK;
if (Name.find("PCMPESTRI") != Name.npos && Name != "PCMPESTRI")
@@ -424,7 +424,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
Spec->insnContext = insnContext();
- const std::vector<CodeGenInstruction::OperandInfo> &OperandList = *Operands;
+ const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands;
unsigned operandIndex;
unsigned numOperands = OperandList.size();
@@ -440,7 +440,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
if (OperandList[operandIndex].Constraints.size()) {
- const CodeGenInstruction::ConstraintInfo &Constraint =
+ const CGIOperandList::ConstraintInfo &Constraint =
OperandList[operandIndex].Constraints[0];
if (Constraint.isTied()) {
operandMapping[operandIndex] = Constraint.getTiedOperand();
@@ -587,6 +587,20 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
HANDLE_OPERAND(memory)
HANDLE_OPTIONAL(relocation)
break;
+ case X86Local::RawFrmImm8:
+ // operand 1 is a 16-bit immediate
+ // operand 2 is an 8-bit immediate
+ assert(numPhysicalOperands == 2 &&
+ "Unexpected number of operands for X86Local::RawFrmImm8");
+ HANDLE_OPERAND(immediate)
+ HANDLE_OPERAND(immediate)
+ break;
+ case X86Local::RawFrmImm16:
+ // operand 1 is a 16-bit immediate
+ // operand 2 is a 16-bit immediate
+ HANDLE_OPERAND(immediate)
+ HANDLE_OPERAND(immediate)
+ break;
case X86Local::MRMInitReg:
// Ignored.
break;
@@ -829,10 +843,13 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("GR8", TYPE_R8)
TYPE("VR128", TYPE_XMM128)
TYPE("f128mem", TYPE_M128)
+ TYPE("f256mem", TYPE_M256)
TYPE("FR64", TYPE_XMM64)
TYPE("f64mem", TYPE_M64FP)
+ TYPE("sdmem", TYPE_M64FP)
TYPE("FR32", TYPE_XMM32)
TYPE("f32mem", TYPE_M32FP)
+ TYPE("ssmem", TYPE_M32FP)
TYPE("RST", TYPE_ST)
TYPE("i128mem", TYPE_M128)
TYPE("i64i32imm_pcrel", TYPE_REL64)
@@ -840,6 +857,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i32imm_pcrel", TYPE_REL32)
TYPE("SSECC", TYPE_IMM3)
TYPE("brtarget", TYPE_RELv)
+ TYPE("uncondbrtarget", TYPE_RELv)
TYPE("brtarget8", TYPE_REL8)
TYPE("f80mem", TYPE_M80FP)
TYPE("lea32mem", TYPE_LEA)
@@ -924,7 +942,10 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString
ENCODING("i32mem", ENCODING_RM)
ENCODING("i64mem", ENCODING_RM)
ENCODING("i8mem", ENCODING_RM)
+ ENCODING("ssmem", ENCODING_RM)
+ ENCODING("sdmem", ENCODING_RM)
ENCODING("f128mem", ENCODING_RM)
+ ENCODING("f256mem", ENCODING_RM)
ENCODING("f64mem", ENCODING_RM)
ENCODING("f32mem", ENCODING_RM)
ENCODING("i128mem", ENCODING_RM)
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index db4d96dda032..c043b909b42f 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -22,7 +22,7 @@
#include "CodeGenTarget.h"
#include "Record.h"
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/SmallVector.h"
namespace llvm {
@@ -76,7 +76,8 @@ private:
/// The operands of the instruction, as listed in the CodeGenInstruction.
/// They are not one-to-one with operands listed in the MCInst; for example,
/// memory operands expand to 5 operands in the MCInst
- const std::vector<CodeGenInstruction::OperandInfo>* Operands;
+ const std::vector<CGIOperandList::OperandInfo>* Operands;
+
/// The description of the instruction that is emitted into the instruction
/// info table
InstructionSpecifier* Spec;
diff --git a/utils/Target/ARM/analyze-match-table.py b/utils/Target/ARM/analyze-match-table.py
new file mode 100644
index 000000000000..aa952d40085a
--- /dev/null
+++ b/utils/Target/ARM/analyze-match-table.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+def analyze_match_table(path):
+ # Extract the instruction table.
+ data = open(path).read()
+ start = data.index("static const MatchEntry MatchTable")
+ end = data.index("\n};\n", start)
+ lines = data[start:end].split("\n")[1:]
+
+ # Parse the instructions.
+ insns = []
+ for ln in lines:
+ ln = ln.split("{", 1)[1]
+ ln = ln.rsplit("}", 1)[0]
+ a,bc = ln.split("{", 1)
+ b,c = bc.split("}", 1)
+ code, string, converter, _ = [s.strip()
+ for s in a.split(",")]
+ items = [s.strip() for s in b.split(",")]
+ _,features = [s.strip() for s in c.split(",")]
+ assert string[0] == string[-1] == '"'
+ string = string[1:-1]
+ insns.append((code,string,converter,items,features))
+
+ # For every mnemonic, compute whether or not it can have a carry setting
+ # operand and whether or not it can have a predication code.
+ mnemonic_flags = {}
+ for insn in insns:
+ mnemonic = insn[1]
+ items = insn[3]
+ flags = mnemonic_flags[mnemonic] = mnemonic_flags.get(mnemonic, set())
+ flags.update(items)
+
+ mnemonics = set(mnemonic_flags)
+ ccout_mnemonics = set(m for m in mnemonics
+ if 'MCK_CCOut' in mnemonic_flags[m])
+ condcode_mnemonics = set(m for m in mnemonics
+ if 'MCK_CondCode' in mnemonic_flags[m])
+ noncondcode_mnemonics = mnemonics - condcode_mnemonics
+ print ' || '.join('Mnemonic == "%s"' % m
+ for m in ccout_mnemonics)
+ print ' || '.join('Mnemonic == "%s"' % m
+ for m in noncondcode_mnemonics)
+
+def main():
+ import sys
+ if len(sys.argv) == 1:
+ import os
+ from lit.Util import capture
+ llvm_obj_root = capture(["llvm-config", "--obj-root"])
+ file = os.path.join(llvm_obj_root,
+ "lib/Target/ARM/ARMGenAsmMatcher.inc")
+ elif len(sys.argv) == 2:
+ file = sys.argv[1]
+ else:
+ raise NotImplementedError
+
+ analyze_match_table(file)
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
index 39ec1ccda9c0..5e8369cdd326 100755
--- a/utils/buildit/build_llvm
+++ b/utils/buildit/build_llvm
@@ -105,7 +105,7 @@ if [ "$ARM_HOSTED_BUILD" = yes ]; then
T=`xcrun -sdk $SDKROOT -find ${prog}`
fi
echo '#!/bin/sh' > $P || exit 1
- echo 'exec '$T' -arch armv6 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1
+ echo 'exec '$T' -arch armv7 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1
chmod a+x $P || exit 1
done
@@ -174,11 +174,6 @@ 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.
@@ -269,8 +264,11 @@ else
-exec lipo -extract ppc7400 -extract i386 -extract x86_64 {} -output {} \;
fi
-# The Hello dylib is an example of how to build a pass. No need to install it.
-rm $DEST_DIR$DEST_ROOT/lib/LLVMHello.dylib
+# The Hello dylib is an example of how to build a pass.
+# The BugpointPasses module is only used to test bugpoint.
+# These unversioned dylibs cause verification failures, so do not install them.
+rm $DEST_DIR$DEST_ROOT/lib/libLLVMHello.dylib
+rm $DEST_DIR$DEST_ROOT/lib/libBugpointPasses.dylib
# Compress manpages
MDIR=$DEST_DIR$DEST_ROOT/share/man/man1
diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el
index b1af853883ad..3780624b5a43 100644
--- a/utils/emacs/llvm-mode.el
+++ b/utils/emacs/llvm-mode.el
@@ -19,7 +19,7 @@
;; 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)
+ `(,(regexp-opt '("void" "i[0-9]+" "float" "double" "type" "label" "opaque") 'words) . font-lock-type-face)
;; Integer literals
'("\\b[-]?[0-9]+\\b" . font-lock-preprocessor-face)
;; Floating point constants
@@ -27,15 +27,20 @@
;; 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)
+ `(,(regexp-opt '("begin" "end" "true" "false" "zeroinitializer" "declare"
+ "define" "global" "constant" "const" "internal" "linkonce" "linkonce_odr"
+ "weak" "weak_odr" "appending" "uninitialized" "implementation" "..."
+ "null" "undef" "to" "except" "not" "target" "endian" "little" "big"
+ "pointersize" "deplibs" "volatile" "fastcc" "coldcc" "cc") 'words) . 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)
+ `(,(regexp-opt '("add" "sub" "mul" "div" "rem" "and" "or" "xor"
+ "setne" "seteq" "setlt" "setgt" "setle" "setge") 'words) . 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)
+ `(,(regexp-opt '("phi" "tail" "call" "cast" "select" "to" "shl" "shr" "vaarg" "vanext") 'words) . font-lock-keyword-face)
;; Control instructions
- '("\\bret\\b\\|\\bbr\\b\\|\\bswitch\\b\\|\\binvoke\\b\\|\\bunwind\\b\\|\\bunreachable\\b" . font-lock-keyword-face)
+ `(,(regexp-opt '("ret" "br" "switch" "invoke" "unwind" "unreachable") 'words) . font-lock-keyword-face)
;; Memory operators
- '("\\bmalloc\\b\\|\\balloca\\b\\|\\bfree\\b\\|\\bload\\b\\|\\bstore\\b\\|\\bgetelementptr\\b" . font-lock-keyword-face)
+ `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr") 'words) . font-lock-keyword-face)
)
"Syntax highlighting for LLVM"
)
diff --git a/utils/emacs/tablegen-mode.el b/utils/emacs/tablegen-mode.el
index 833c16c599d4..3853ce66a285 100644
--- a/utils/emacs/tablegen-mode.el
+++ b/utils/emacs/tablegen-mode.el
@@ -12,13 +12,11 @@
(make-face 'td-decorators-face)
(defvar tablegen-font-lock-keywords
- (let ((kw (mapconcat 'identity
- '("class" "defm" "def" "field" "include" "in"
+ (let ((kw (regexp-opt '("class" "defm" "def" "field" "include" "in"
"let" "multiclass")
- "\\|"))
- (type-kw (mapconcat 'identity
- '("bit" "bits" "code" "dag" "int" "list" "string")
- "\\|"))
+ 'words))
+ (type-kw (regexp-opt '("bit" "bits" "code" "dag" "int" "list" "string")
+ 'words))
)
(list
;; Comments
@@ -36,10 +34,10 @@
'("^[ \t]*\\(@.+\\)" 1 'td-decorators-face)
;; Keywords
- (cons (concat "\\<\\(" kw "\\)\\>[ \n\t(]") 1)
+ (cons (concat kw "[ \n\t(]") 1)
;; Type keywords
- (cons (concat "\\<\\(" type-kw "\\)[ \n\t(]") 1)
+ (cons (concat type-kw "[ \n\t(]") 1)
))
"Additional expressions to highlight in TableGen mode.")
(put 'tablegen-mode 'font-lock-defaults '(tablegen-font-lock-keywords))
diff --git a/utils/findmisopt b/utils/findmisopt
index b7ffbd9947d5..f2a872c6dc3e 100755
--- a/utils/findmisopt
+++ b/utils/findmisopt
@@ -7,7 +7,7 @@
# 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),
+# Given a bitcode 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
@@ -21,7 +21,7 @@
#
# Where:
# bcfile
-# is the bytecode file input (the unoptimized working case)
+# is the bitcode file input (the unoptimized working case)
# outdir
# is a directory into which intermediate results are placed
# progargs
diff --git a/utils/findoptdiff b/utils/findoptdiff
index 4f8d08dbffe1..7a2eab05d71a 100755
--- a/utils/findoptdiff
+++ b/utils/findoptdiff
@@ -14,7 +14,7 @@
# 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
+# The script takes two bitcode 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.
#
@@ -39,9 +39,9 @@
# llvm2
# is the path to the second llvm build dir
# bc1
-# is the bytecode file for the first llvm environment
+# is the bitcode file for the first llvm environment
# bc2
-# is the bytecode file for the second llvm environment
+# is the bitcode file for the second llvm environment
# filter1
# is an optional filter for filtering the llvm1 generated assembly
# filter2
diff --git a/utils/fpcmp/Makefile b/utils/fpcmp/Makefile
index fd2f7477bb4e..81db3b9c3f6e 100644
--- a/utils/fpcmp/Makefile
+++ b/utils/fpcmp/Makefile
@@ -1,15 +1,15 @@
##===- 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
+USEDLIBS = LLVMSupport.a
NO_INSTALL = 1
include $(LEVEL)/Makefile.common
diff --git a/utils/kate/README b/utils/kate/README
new file mode 100644
index 000000000000..efe53b7e237e
--- /dev/null
+++ b/utils/kate/README
@@ -0,0 +1,12 @@
+-*- llvm/utils/kate/README -*-
+
+These are syntax highlighting files for the Kate editor. Included are:
+
+* llvm.xml
+
+ Syntax Highlighting Mode for the KDE Kate editor. To install just copy
+ this file to ~/.kde/share/apps/katepart/syntax (or better yet, symlink it).
+
+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/kate/llvm.xml b/utils/kate/llvm.xml
new file mode 100644
index 000000000000..074fa16cb884
--- /dev/null
+++ b/utils/kate/llvm.xml
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE language SYSTEM "language.dtd">
+<language name="LLVM" section="Sources"
+ version="1.00" kateversion="3.4.4"
+ extensions="*.ll"
+ mimetype=""
+ author="LLVM Team"
+ license="LLVM Release License">
+ <highlighting>
+ <list name="keywords">
+ <item> begin </item>
+ <item> end </item>
+ <item> true </item>
+ <item> false </item>
+ <item> declare </item>
+ <item> define </item>
+ <item> global </item>
+ <item> constant </item>
+ <item> gc </item>
+ <item> module </item>
+ <item> asm </item>
+ <item> target </item>
+ <item> datalayout </item>
+ <item> null </item>
+ <item> undef </item>
+ <item> blockaddress </item>
+ <item> sideeffect </item>
+ <item> alignstack </item>
+ <item> to </item>
+ <item> unwind </item>
+ <item> nuw </item>
+ <item> nsw </item>
+ <item> inbounds </item>
+ <item> tail </item>
+ <item> triple </item>
+ <item> type </item>
+ <item> align </item>
+ <item> alias </item>
+ </list>
+ <list name="linkage-types">
+ <item> private </item>
+ <item> linker_private </item>
+ <item> linker_private_weak </item>
+ <item> linker_private_weak_def_auto </item>
+ <item> internal </item>
+ <item> available_externally </item>
+ <item> linkonce </item>
+ <item> weak </item>
+ <item> common </item>
+ <item> appending </item>
+ <item> extern_weak </item>
+ <item> linkonce_odr </item>
+ <item> weak_odr </item>
+ <item> dllimport </item>
+ <item> dllexport </item>
+ </list>
+ <list name="calling-conventions">
+ <item> ccc </item>
+ <item> fastcc </item>
+ <item> coldcc </item>
+ <item> cc </item>
+ </list>
+ <list name="visibility-styles">
+ <item> default </item>
+ <item> hidden </item>
+ <item> protected </item>
+ </list>
+ <list name="parameter-attributes">
+ <item> zeroext </item>
+ <item> signext </item>
+ <item> inreg </item>
+ <item> byval </item>
+ <item> sret </item>
+ <item> noalias </item>
+ <item> nocapture </item>
+ <item> nest </item>
+ </list>
+ <list name="function-attributes">
+ <item> alignstack </item>
+ <item> alwaysinline </item>
+ <item> inlinehint </item>
+ <item> naked </item>
+ <item> noimplicitfloat </item>
+ <item> noinline </item>
+ <item> noredzone </item>
+ <item> noreturn </item>
+ <item> nounwind </item>
+ <item> optsize </item>
+ <item> readnone </item>
+ <item> readonly </item>
+ <item> ssp </item>
+ <item> sspreq </item>
+ </list>
+ <list name="types">
+ <item> float </item>
+ <item> double </item>
+ <item> fp128 </item>
+ <item> x86_fp80 </item>
+ <item> ppc_fp128 </item>
+ <item> x86mmx </item>
+ <item> void </item>
+ <item> label </item>
+ <item> metadata </item>
+ <item> opaque </item>
+ </list>
+ <list name="intrinsic-global-variables">
+ <item> llvm.used </item>
+ <item> llvm.compiler.used </item>
+ <item> llvm.global_ctors </item>
+ <item> llvm.global_dtors </item>
+ </list>
+ <list name="instructions">
+ <item> ret </item>
+ <item> br </item>
+ <item> switch </item>
+ <item> indirectbr </item>
+ <item> invoke </item>
+ <item> unwind </item>
+ <item> unreachable </item>
+ <item> add </item>
+ <item> fadd </item>
+ <item> sub </item>
+ <item> fsub </item>
+ <item> mul </item>
+ <item> fmul </item>
+ <item> udiv </item>
+ <item> sdiv </item>
+ <item> fdiv </item>
+ <item> urem </item>
+ <item> srem </item>
+ <item> frem </item>
+ <item> shl </item>
+ <item> lshr </item>
+ <item> ashr </item>
+ <item> and </item>
+ <item> or </item>
+ <item> xor </item>
+ <item> extractelement </item>
+ <item> insertelement </item>
+ <item> shufflevector </item>
+ <item> extractvalue </item>
+ <item> insertvalue </item>
+ <item> alloca </item>
+ <item> load </item>
+ <item> store </item>
+ <item> getelementptr </item>
+ <item> trunc </item>
+ <item> zext </item>
+ <item> sext </item>
+ <item> fptrunc </item>
+ <item> fpext </item>
+ <item> fptoui </item>
+ <item> fptosi </item>
+ <item> uitofp </item>
+ <item> sitofp </item>
+ <item> ptrtoint </item>
+ <item> inttoptr </item>
+ <item> bitcast </item>
+ <item> icmp </item>
+ <item> fcmp </item>
+ <item> phi </item>
+ <item> select </item>
+ <item> call </item>
+ <item> va_arg </item>
+ </list>
+ <list name="conditions">
+ <item> eq </item>
+ <item> ne </item>
+ <item> ugt </item>
+ <item> uge </item>
+ <item> ult </item>
+ <item> ule </item>
+ <item> sgt </item>
+ <item> sge </item>
+ <item> slt </item>
+ <item> sle </item>
+ <item> oeq </item>
+ <item> ogt </item>
+ <item> oge </item>
+ <item> olt </item>
+ <item> ole </item>
+ <item> one </item>
+ <item> ord </item>
+ <item> ueq </item>
+ <item> une </item>
+ <item> uno </item>
+ </list>
+ <contexts>
+ <context name="llvm" attribute="Normal Text" lineEndContext="#stay">
+ <DetectSpaces />
+ <AnyChar String="@%" attribute="Symbol" context="symbol" />
+
+ <DetectChar char="{" beginRegion="Brace1" />
+ <DetectChar char="}" endRegion="Brace1" />
+ <DetectChar char=";" attribute="Comment" context="comment" />
+ <DetectChar attribute="String" context="string" char="&quot;" />
+ <RegExpr String="i[0-9]+" attribute="Data Type" context="#stay" />
+ <RegExpr attribute="Symbol" String="[-a-zA-Z$._][-a-zA-Z$._0-9]*:" context="#stay" />
+ <Int attribute="Int" context="#stay" />
+
+ <keyword attribute="Keyword" String="keywords" />
+ <keyword attribute="Keyword" String="linkage-types" />
+ <keyword attribute="Keyword" String="calling-conventions" />
+ <keyword attribute="Keyword" String="visibility-styles" />
+ <keyword attribute="Keyword" String="parameter-attributes" />
+ <keyword attribute="Keyword" String="function-attributes" />
+ <keyword attribute="Data Type" String="types" />
+ <keyword attribute="Keyword" String="intrinsic-global-variables" />
+ <keyword attribute="Keyword" String="instructions" />
+ <keyword attribute="Keyword" String="conditions" />
+ </context>
+
+ <context name="symbol" attribute="Symbol" lineEndContext="#pop">
+ <DetectChar attribute="Symbol" context="symbol-string" char="&quot;" />
+ <RegExpr attribute="Symbol" String="([-a-zA-Z$._][-a-zA-Z$._0-9]*|[0-9]+)" context="#pop" />
+ </context>
+
+ <context name="symbol-string" attribute="Symbol" lineEndContext="#stay">
+ <DetectChar attribute="Symbol" context="#pop#pop" char="&quot;" />
+ </context>
+
+ <context name="string" attribute="String" lineEndContext="#stay">
+ <DetectChar attribute="String" context="#pop" char="&quot;" />
+ </context>
+
+ <context name="comment" attribute="Comment" lineEndContext="#pop">
+ <DetectSpaces />
+ <!-- TODO: Add FileCheck syntax highlighting -->
+ <IncludeRules context="##Alerts" />
+ <DetectIdentifier />
+ </context>
+ </contexts>
+ <itemDatas>
+ <itemData name="Normal Text" defStyleNum="dsNormal" />
+ <itemData name="Keyword" defStyleNum="dsKeyword" />
+ <itemData name="Data Type" defStyleNum="dsDataType" />
+ <itemData name="Int" defStyleNum="dsDecVal" />
+ <itemData name="Hex" defStyleNum="dsBaseN" />
+ <itemData name="Float" defStyleNum="dsFloat" />
+ <itemData name="String" defStyleNum="dsString" />
+ <itemData name="Comment" defStyleNum="dsComment" />
+ <itemData name="Function" defStyleNum="dsFunction" />
+ <itemData name="Symbol" defStyleNum="dsFunction" />
+ </itemDatas>
+ </highlighting>
+ <general>
+ <comments>
+ <comment name="singleLine" start=";" />
+ </comments>
+ <keywords casesensitive="1" weakDeliminator="." />
+ </general>
+</language>
+<!--
+// kate: space-indent on; indent-width 2; replace-tabs on;
+-->
diff --git a/utils/lit/TODO b/utils/lit/TODO
index 4d00d2c1cfcd..6d7f7ea529ae 100644
--- a/utils/lit/TODO
+++ b/utils/lit/TODO
@@ -2,18 +2,8 @@
- Add --show-unsupported, don't show by default?
- - Finish documentation.
-
- Optionally use multiprocessing.
- - Support llvmc and ocaml tests.
-
- Support valgrind in all configs, and LLVM style valgrind.
- - Provide test suite config for running unit tests.
-
- Support a timeout / ulimit.
-
- - Support "disabling" tests? The advantage of making this distinct from XFAIL
- is it makes it more obvious that it is a temporary measure (and lit can put
- in a separate category).
diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py
index ac4859137e54..7ca1b9c4c634 100644
--- a/utils/lit/lit/LitConfig.py
+++ b/utils/lit/lit/LitConfig.py
@@ -8,6 +8,9 @@ class LitConfig:
easily.
"""
+ # Provide access to Test module.
+ import Test
+
# Provide access to built-in formats.
import LitFormats as formats
@@ -82,6 +85,22 @@ class LitConfig:
return self.bashPath
+ def getToolsPath(self, dir, paths, tools):
+ import os, Util
+ if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
+ if not Util.checkToolsPath(dir, tools):
+ return None
+ else:
+ dir = Util.whichTools(tools, paths)
+
+ # bash
+ self.bashPath = Util.which('bash', dir)
+ if self.bashPath is None:
+ self.warning("Unable to find 'bash.exe'.")
+ self.bashPath = ''
+
+ return dir
+
def _write_message(self, kind, message):
import inspect, os, sys
diff --git a/utils/lit/lit/LitFormats.py b/utils/lit/lit/LitFormats.py
index e86f103fe6b2..931d107109b3 100644
--- a/utils/lit/lit/LitFormats.py
+++ b/utils/lit/lit/LitFormats.py
@@ -1,2 +1,3 @@
+from TestFormats import FileBasedTest
from TestFormats import GoogleTest, ShTest, TclTest
from TestFormats import SyntaxCheckTest, OneCommandPerFileTest
diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py
index 7ffbd2bf7663..6dda2fdb608d 100644
--- a/utils/lit/lit/TestFormats.py
+++ b/utils/lit/lit/TestFormats.py
@@ -1,15 +1,15 @@
import os
-import platform
+import sys
import Test
import TestRunner
import Util
-kIsWindows = platform.system() == 'Windows'
+kIsWindows = sys.platform in ['win32', 'cygwin']
class GoogleTest(object):
def __init__(self, test_sub_dir, test_suffix):
- self.test_sub_dir = str(test_sub_dir)
+ self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';')
self.test_suffix = str(test_suffix)
# On Windows, assume tests will also end in '.exe'.
@@ -28,7 +28,10 @@ class GoogleTest(object):
try:
lines = Util.capture([path, '--gtest_list_tests'],
- env=localConfig.environment).split('\n')
+ env=localConfig.environment)
+ if kIsWindows:
+ lines = lines.replace('\r', '')
+ lines = lines.split('\n')
except:
litConfig.error("unable to discover google-tests in %r" % path)
raise StopIteration
@@ -44,7 +47,7 @@ class GoogleTest(object):
index += 1
while len(nested_tests) > index:
nested_tests.pop()
-
+
ln = ln[index*2:]
if ln.endswith('.'):
nested_tests.append(ln)
@@ -56,10 +59,14 @@ class GoogleTest(object):
source_path = testSuite.getSourcePath(path_in_suite)
for filename in os.listdir(source_path):
# Check for the one subdirectory (build directory) tests will be in.
- if filename != self.test_sub_dir:
- continue
+ if not '.' in self.test_sub_dir:
+ if not os.path.normcase(filename) in self.test_sub_dir:
+ continue
filepath = os.path.join(source_path, filename)
+ if not os.path.isdir(filepath):
+ continue
+
for subfilename in os.listdir(filepath):
if subfilename.endswith(self.test_suffix):
execpath = os.path.join(filepath, subfilename)
@@ -84,7 +91,7 @@ class GoogleTest(object):
out, err, exitCode = TestRunner.executeCommand(
cmd, env=test.config.environment)
-
+
if not exitCode:
return Test.PASS,''
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index 0eb51a829408..dba78143bee2 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -8,6 +8,8 @@ import Util
import platform
import tempfile
+import re
+
class InternalShellError(Exception):
def __init__(self, command, message):
self.command = command
@@ -178,6 +180,13 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
input = subprocess.PIPE
+ # Explicitly close any redirected files. We need to do this now because we
+ # need to release any handles we may have on the temporary files (important
+ # on Win32, for example). Since we have already spawned the subprocess, our
+ # handles have already been transferred so we do not need them anymore.
+ for f in opened_files:
+ f.close()
+
# FIXME: There is probably still deadlock potential here. Yawn.
procData = [None] * len(procs)
procData[-1] = procs[-1].communicate()
@@ -215,10 +224,6 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
exitCode = res
- # Explicitly close any redirected files.
- for f in opened_files:
- f.close()
-
# Remove any named temporary files we created.
for f in named_temp_files:
try:
@@ -441,11 +446,15 @@ def parseIntegratedTestScript(test, normalize_slashes=False):
if ln[ln.index('END.'):].strip() == 'END.':
break
- # Apply substitutions to the script.
+ # Apply substitutions to the script. Allow full regular
+ # expression syntax. Replace each matching occurrence of regular
+ # expression pattern a with substitution b in line ln.
def processLine(ln):
# Apply substitutions
for a,b in substitutions:
- ln = ln.replace(a,b)
+ if kIsWindows:
+ b = b.replace("\\","\\\\")
+ ln = re.sub(a, b, ln)
# Strip the trailing newline and any extra whitespace.
return ln.strip()
diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py
index 5c1b27394857..0d9bc00a8357 100644
--- a/utils/lit/lit/TestingConfig.py
+++ b/utils/lit/lit/TestingConfig.py
@@ -10,12 +10,14 @@ class TestingConfig:
if config is None:
# Set the environment based on the command line arguments.
environment = {
+ 'LIBRARY_PATH' : os.environ.get('LIBRARY_PATH',''),
'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH',''),
'PATH' : os.pathsep.join(litConfig.path +
[os.environ.get('PATH','')]),
'PATHEXT' : os.environ.get('PATHEXT',''),
'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''),
'LLVM_DISABLE_CRT_DEBUG' : '1',
+ 'PRINTF_EXPONENT_DIGITS' : '2',
}
config = TestingConfig(parent,
diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py
index 414b714c82c3..5635f50baef3 100644
--- a/utils/lit/lit/Util.py
+++ b/utils/lit/lit/Util.py
@@ -64,7 +64,11 @@ def which(command, paths = None):
paths = os.defpath
# Get suffixes to search.
- pathext = os.environ.get('PATHEXT', '').split(os.pathsep)
+ # On Cygwin, 'PATHEXT' may exist but it should not be used.
+ if os.pathsep == ';':
+ pathext = os.environ.get('PATHEXT', '').split(';')
+ else:
+ pathext = ['']
# Search the paths...
for path in paths.split(os.pathsep):
@@ -75,6 +79,18 @@ def which(command, paths = None):
return None
+def checkToolsPath(dir, tools):
+ for tool in tools:
+ if not os.path.exists(os.path.join(dir, tool)):
+ return False;
+ return True;
+
+def whichTools(tools, paths):
+ for path in paths.split(os.pathsep):
+ if checkToolsPath(path, tools):
+ return path
+ return None
+
def printHistogram(items, title = 'Items'):
import itertools, math
diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py
index 01026023d29b..f3fbb1cd8276 100644
--- a/utils/lit/lit/__init__.py
+++ b/utils/lit/lit/__init__.py
@@ -1,10 +1,10 @@
"""'lit' Testing Tool"""
-from lit import main
+from main import main
__author__ = 'Daniel Dunbar'
__email__ = 'daniel@zuster.org'
-__versioninfo__ = (0, 1, 0)
-__version__ = '.'.join(map(str, __versioninfo__))
+__versioninfo__ = (0, 2, 0)
+__version__ = '.'.join(map(str, __versioninfo__)) + 'dev'
__all__ = []
diff --git a/utils/lit/lit/lit.py b/utils/lit/lit/main.py
index 13d263009ddd..13d263009ddd 100755
--- a/utils/lit/lit/lit.py
+++ b/utils/lit/lit/main.py
diff --git a/utils/lit/setup.py b/utils/lit/setup.py
index e6ae3d880488..738ee23776d8 100644
--- a/utils/lit/setup.py
+++ b/utils/lit/setup.py
@@ -3,7 +3,7 @@ import lit
# FIXME: Support distutils?
from setuptools import setup, find_packages
setup(
- name = "Lit",
+ name = "lit",
version = lit.__version__,
author = lit.__author__,
@@ -14,15 +14,16 @@ setup(
description = "A Software Testing Tool",
keywords = 'test C++ automatic discovery',
long_description = """\
-Lit
-+++
+*lit*
++++++
About
=====
-Lit is a portable tool for executing LLVM and Clang style test suites,
-summarizing their results, and providing indication of failures. Lit is designed
-to be a lightweight testing tool with as simple a user interface as possible.
+*lit* is a portable tool for executing LLVM and Clang style test suites,
+summarizing their results, and providing indication of failures. *lit* is
+designed to be a lightweight testing tool with as simple a user interface as
+possible.
Features
@@ -37,15 +38,15 @@ Features
Documentation
=============
-The offical Lit documentation is in the man page, available online in the `LLVM
-Command Guide http://llvm.org/cmds/lit.html`_.
+The offical *lit* documentation is in the man page, available online at the LLVM
+Command Guide: http://llvm.org/cmds/lit.html.
Source
======
-The Lit source is available as part of LLVM, in the `LLVM SVN repository
-<http://llvm.org/svn/llvm-project/llvm/trunk/utils/lit`_.
+The *lit* source is available as part of LLVM, in the LLVM SVN repository:
+http://llvm.org/svn/llvm-project/llvm/trunk/utils/lit.
""",
classifiers=[
@@ -55,7 +56,7 @@ The Lit source is available as part of LLVM, in the `LLVM SVN repository
'License :: OSI Approved :: University of Illinois/NCSA Open Source License',
'Natural Language :: English',
'Operating System :: OS Independent',
- 'Progamming Language :: Python',
+ 'Programming Language :: Python',
'Topic :: Software Development :: Testing',
],
diff --git a/utils/llvm-lit/CMakeLists.txt b/utils/llvm-lit/CMakeLists.txt
new file mode 100644
index 000000000000..602cc881cd5a
--- /dev/null
+++ b/utils/llvm-lit/CMakeLists.txt
@@ -0,0 +1,12 @@
+configure_file(
+ llvm-lit.in
+ ${LLVM_TOOLS_BINARY_DIR}/llvm-lit
+ )
+
+install(FILES
+ ${LLVM_TOOLS_BINARY_DIR}/llvm-lit
+ DESTINATION bin
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE
+ )
diff --git a/utils/llvm-lit/llvm-lit.in b/utils/llvm-lit/llvm-lit.in
index 3ff2c2489c45..1df1747a1cc6 100644
--- a/utils/llvm-lit/llvm-lit.in
+++ b/utils/llvm-lit/llvm-lit.in
@@ -13,9 +13,15 @@ sys.path.append(os.path.join(llvm_source_root, 'utils', 'lit'))
# Set up some builtin parameters, so that by default the LLVM test suite
# configuration file knows how to find the object tree.
builtin_parameters = {
+ 'build_config' : "@CMAKE_CFG_INTDIR@",
+ 'build_mode' : "@RUNTIME_BUILD_MODE@",
'llvm_site_config' : os.path.join(llvm_obj_root, 'test', 'lit.site.cfg')
}
+clang_site_config = os.path.join(llvm_obj_root, 'tools', 'clang', 'test', 'lit.site.cfg')
+if os.path.exists(clang_site_config):
+ builtin_parameters['clang_site_config'] = clang_site_config
+
if __name__=='__main__':
import lit
lit.main(builtin_parameters)
diff --git a/utils/llvm-native-gcc b/utils/llvm-native-gcc
index b3cecb14118f..91a557cc161d 100755
--- a/utils/llvm-native-gcc
+++ b/utils/llvm-native-gcc
@@ -193,10 +193,10 @@ native-build [OPTIONS...] FILE
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
+an LLVM back-end (CBE by default) over the resulting bitcode, and then
compiling the resulting code to a native object file.
-If called as "native-build", it compiles bytecode to native code, and takes
+If called as "native-build", it compiles bitcode to native code, and takes
different options.
=head1 OPTIONS
diff --git a/utils/llvm-native-gxx b/utils/llvm-native-gxx
index 75164af237ef..db547f654e2f 100755
--- a/utils/llvm-native-gxx
+++ b/utils/llvm-native-gxx
@@ -193,10 +193,10 @@ native-build [OPTIONS...] FILE
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
+an LLVM back-end (CBE by default) over the resulting bitcode, and then
compiling the resulting code to a native object file.
-If called as "native-build", it compiles bytecode to native code, and takes
+If called as "native-build", it compiles bitcode to native code, and takes
different options.
=head1 OPTIONS
diff --git a/utils/not/CMakeLists.txt b/utils/not/CMakeLists.txt
index 407c82eeeadd..155d2e3ae7e4 100644
--- a/utils/not/CMakeLists.txt
+++ b/utils/not/CMakeLists.txt
@@ -2,7 +2,7 @@ add_executable(not
not.cpp
)
-target_link_libraries(not LLVMSystem)
+target_link_libraries(not LLVMSupport)
if( MINGW )
target_link_libraries(not imagehlp psapi)
endif( MINGW )
diff --git a/utils/not/Makefile b/utils/not/Makefile
index fef4802229d2..f37f166c6c7b 100644
--- a/utils/not/Makefile
+++ b/utils/not/Makefile
@@ -1,15 +1,15 @@
##===- utils/not/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 = not
-USEDLIBS = LLVMSupport.a LLVMSystem.a
+USEDLIBS = LLVMSupport.a
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/utils/not/not.cpp b/utils/not/not.cpp
index dd89b8f11c0e..9a924b56a792 100644
--- a/utils/not/not.cpp
+++ b/utils/not/not.cpp
@@ -7,11 +7,21 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/System/Path.h"
-#include "llvm/System/Program.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
int main(int argc, const char **argv) {
sys::Path Program = sys::Program::FindProgramByName(argv[1]);
- return !sys::Program::ExecuteAndWait(Program, argv + 1);
+
+ std::string ErrMsg;
+ int Result = sys::Program::ExecuteAndWait(Program, argv + 1, 0, 0, 0, 0,
+ &ErrMsg);
+ if (Result < 0) {
+ errs() << "Error: " << ErrMsg << "\n";
+ return 1;
+ }
+
+ return Result == 0;
}
diff --git a/utils/profile.pl b/utils/profile.pl
index f9950f97fea8..318011560bc8 100755
--- a/utils/profile.pl
+++ b/utils/profile.pl
@@ -5,7 +5,7 @@
# Synopsis: Insert instrumentation code into a program, run it with the JIT,
# then print out a profile report.
#
-# Syntax: profile.pl [OPTIONS] bytecodefile <arguments>
+# Syntax: profile.pl [OPTIONS] bitcodefile <arguments>
#
# OPTIONS may include one or more of the following:
# -block - Enable basicblock profiling
@@ -56,7 +56,7 @@ while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) {
$LLVMProfOpts .= " " . $_;
}
-die "Must specify LLVM bytecode file as first argument!" if (@ARGV == 0);
+die "Must specify LLVM bitcode file as first argument!" if (@ARGV == 0);
my $BytecodeFile = $ARGV[0];
diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh
new file mode 100755
index 000000000000..e24638e714a3
--- /dev/null
+++ b/utils/release/test-release.sh
@@ -0,0 +1,398 @@
+#!/bin/bash
+#===-- test-release.sh - Test the LLVM release candidates ------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License.
+#
+#===------------------------------------------------------------------------===#
+#
+# Download, build, and test the release candidate for an LLVM release.
+#
+#===------------------------------------------------------------------------===#
+
+set -e
+
+Release=""
+Release_no_dot=""
+RC=""
+do_checkout="yes"
+do_ada="no"
+do_objc="yes"
+do_fortran="yes"
+do_64bit="yes"
+BuildDir="`pwd`"
+
+function usage() {
+ echo "usage: `basename $0` -release X.Y -rc NUM [OPTIONS]"
+ echo ""
+ echo " -release X.Y The release number to test."
+ echo " -rc NUM The pre-release candidate number."
+ echo " -j NUM Number of compile jobs to run. [default: 3]"
+ echo " -build-dir DIR Directory to perform testing in. [default: pwd]"
+ echo " -no-checkout Don't checkout the sources from SVN."
+ echo " -no-64bit Don't test the 64-bit version. [default: yes]"
+ echo " -ada Build Ada. [default: no]"
+ echo " -disable-objc Disable ObjC build. [default: build]"
+ echo " -disable-fortran Disable Fortran build. [default: build]"
+}
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ -release | --release )
+ shift
+ Release="$1"
+ Release_no_dot="`echo $1 | sed -e 's,\.,,'`"
+ ;;
+ -rc | --rc | -RC | --RC )
+ shift
+ RC=$1
+ ;;
+ -j* )
+ NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`"
+ if [ -z "$NumJobs" ]; then
+ shift
+ NumJobs="$1"
+ fi
+ ;;
+ -build-dir | --build-dir | -builddir | --builddir )
+ shift
+ BuildDir="$1"
+ ;;
+ -no-checkout | --no-checkout )
+ do_checkout="no"
+ ;;
+ -no-64bit | --no-64bit )
+ do_64bit="no"
+ ;;
+ -ada | --ada )
+ do_ada="yes"
+ ;;
+ -disable-objc | --disable-objc )
+ do_objc="no"
+ ;;
+ -disable-fortran | --disable-fortran )
+ echo "WARNING: Do you *really* need to disable Fortran?"
+ sleep 5
+ do_fortran="no"
+ ;;
+ -help | --help | -h | --h | -\? )
+ usage
+ exit 0
+ ;;
+ * )
+ echo "unknown option: $1"
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# Check required arguments.
+if [ -z "$Release" ]; then
+ echo "No release number specified!"
+ exit 1
+fi
+if [ -z "$RC" ]; then
+ echo "No release candidate number specified!"
+ exit 1
+fi
+
+# Figure out how many make processes to run.
+if [ -z "$NumJobs" ]; then
+ NumJobs=`sysctl -n hw.activecpu 2> /dev/null || true`
+fi
+if [ -z "$NumJobs" ]; then
+ NumJobs=`sysctl -n hw.ncpu 2> /dev/null || true`
+fi
+if [ -z "$NumJobs" ]; then
+ NumJobs=`grep -c processor /proc/cpuinfo 2> /dev/null || true`
+fi
+if [ -z "$NumJobs" ]; then
+ NumJobs=3
+fi
+
+# Location of sources.
+llvmCore_srcdir=$BuildDir/llvmCore-$Release-rc$RC.src
+llvmgcc42_srcdir=$BuildDir/llvmgcc42-$Release-rc$RC.src
+
+# Location of log files.
+LogDirName="$Release-rc$RC.logs"
+LogDir=$BuildDir/$LogDirName
+mkdir -p $LogDir
+
+# SVN URLs for the sources.
+Base_url="http://llvm.org/svn/llvm-project"
+llvmCore_RC_url="$Base_url/llvm/tags/RELEASE_$Release_no_dot/rc$RC"
+llvmgcc42_RC_url="$Base_url/llvm-gcc-4.2/tags/RELEASE_$Release_no_dot/rc$RC"
+clang_RC_url="$Base_url/cfe/tags/RELEASE_$Release_no_dot/rc$RC"
+test_suite_RC_url="$Base_url/test-suite/tags/RELEASE_$Release_no_dot/rc$RC"
+
+# Make sure that the URLs are valid.
+function check_valid_urls() {
+ echo "# Validating SVN URLs"
+ if ! svn ls $llvmCore_RC_url > /dev/null 2>&1 ; then
+ echo "llvm $Release release candidate $RC doesn't exist!"
+ exit 1
+ fi
+ if ! svn ls $llvmgcc42_RC_url > /dev/null 2>&1 ; then
+ echo "llvm-gcc-4.2 $Release release candidate $RC doesn't exist!"
+ exit 1
+ fi
+ if ! svn ls $clang_RC_url > /dev/null 2>&1 ; then
+ echo "clang $Release release candidate $RC doesn't exist!"
+ exit 1
+ fi
+ if ! svn ls $test_suite_RC_url > /dev/null 2>&1 ; then
+ echo "test-suite $Release release candidate $RC doesn't exist!"
+ exit 1
+ fi
+}
+
+# Export sources to the the build directory.
+function export_sources() {
+ check_valid_urls
+
+ echo "# Exporting llvm $Release-RC$RC sources"
+ svn export -q $llvmCore_RC_url $llvmCore_srcdir
+ echo "# Exporting llvm-gcc-4.2 $Release-rc$RC sources"
+ svn export -q $llvmgcc42_RC_url $llvmgcc42_srcdir
+ echo "# Exporting clang $Release-rc$RC sources"
+ svn export -q $clang_RC_url $llvmCore_srcdir/tools/clang
+ echo "# Exporting llvm test suite $Release-rc$RC sources"
+ svn export -q $test_suite_RC_url $llvmCore_srcdir/projects/llvm-test
+}
+
+function configure_llvmCore() {
+ Phase="$1"
+ Flavor="$2"
+ ObjDir="$3"
+ InstallDir="$4"
+ llvmgccDir="$5"
+
+ case $Flavor in
+ Release | Release-64 )
+ Optimized="yes"
+ Assertions="no"
+ ;;
+ Release+Asserts )
+ Optimized="yes"
+ Assertions="yes"
+ ;;
+ Debug )
+ Optimized="no"
+ Assertions="yes"
+ ;;
+ * )
+ echo "# Invalid flavor $Flavor!"
+ echo ""
+ return
+ ;;
+ esac
+
+ cd $ObjDir
+ echo "# Configuring llvm $Release-rc$RC $Flavor"
+ echo "# $llvmCore_srcdir/configure --prefix=$InstallDir \
+ --enable-optimized=$Optimized \
+ --enable-assertions=$Assertions \
+ --with-llvmgccdir=$llvmgccDir"
+ $llvmCore_srcdir/configure --prefix=$InstallDir \
+ --enable-optimized=$Optimized \
+ --enable-assertions=$Assertions \
+ --with-llvmgccdir=$llvmgccDir \
+ > $LogDir/llvm.configure.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ cd -
+}
+
+function build_llvmCore() {
+ Phase="$1"
+ Flavor="$2"
+ ObjDir="$3"
+ ExtraOpts=""
+
+ CompilerFlags=""
+ if [ "$Phase" = "2" ]; then
+ CompilerFlags="CC=$llvmgccDir/bin/llvm-gcc CXX=$llvmgccDir/bin/llvm-g++"
+ fi
+ if [ "$Flavor" = "Release-64" ]; then
+ ExtraOpts="EXTRA_OPTIONS=-m64"
+ fi
+
+ cd $ObjDir
+ echo "# Compiling llvm $Release-rc$RC $Flavor"
+ echo "# make -j $NumJobs VERBOSE=1 $ExtraOpts"
+ make -j $NumJobs VERBOSE=1 $ExtraOpts $CompilerFlags \
+ > $LogDir/llvm.make.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+
+ echo "# Installing llvm $Release-rc$RC $Flavor"
+ echo "# make install"
+ make install \
+ > $LogDir/llvm.install.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ cd -
+}
+
+function test_llvmCore() {
+ Phase="$1"
+ Flavor="$2"
+ ObjDir="$3"
+
+ cd $ObjDir
+ make check \
+ > $LogDir/llvm.check.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ make -C tools/clang test \
+ > $LogDir/clang.check.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ make unittests \
+ > $LogDir/llvm.unittests.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ cd -
+}
+
+function configure_llvm_gcc() {
+ Phase="$1"
+ Flavor="$2"
+ ObjDir="$3"
+ InstallDir="$4"
+ llvmObjDir="$5"
+
+ languages="c,c++"
+ if [ "$do_objc" = "yes" ]; then
+ languages="$languages,objc,obj-c++"
+ fi
+ if [ "$do_fortran" = "yes" ]; then
+ languages="$languages,fortran"
+ fi
+ if [ "$do_ada" = "yes" ]; then
+ languages="$languages,ada"
+ fi
+
+ cd $ObjDir
+ echo "# Configuring llvm-gcc $Release-rc$RC $Flavor"
+ echo "# $llvmgcc42_srcdir/configure --prefix=$InstallDir \
+ --program-prefix=llvm- --enable-llvm=$llvmObjDir \
+ --enable-languages=$languages"
+ $llvmgcc42_srcdir/configure --prefix=$InstallDir \
+ --program-prefix=llvm- --enable-llvm=$llvmObjDir \
+ --enable-languages=$languages \
+ > $LogDir/llvm-gcc.configure.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ cd -
+}
+
+function build_llvm_gcc() {
+ Phase="$1"
+ Flavor="$2"
+ ObjDir="$3"
+ llvmgccDir="$4"
+
+ CompilerFlags=""
+ if [ "$Phase" = "2" ]; then
+ CompilerFlags="CC=$llvmgccDir/bin/llvm-gcc CXX=$llvmgccDir/bin/llvm-g++"
+ fi
+
+ cd $ObjDir
+ echo "# Compiling llvm-gcc $Release-rc$RC $Flavor"
+ echo "# make -j $NumJobs bootstrap LLVM_VERSION_INFO=$Release"
+ make -j $NumJobs bootstrap LLVM_VERSION_INFO=$Release $CompilerFlags \
+ > $LogDir/llvm-gcc.make.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+
+ echo "# Installing llvm-gcc $Release-rc$RC $Flavor"
+ echo "# make install"
+ make install \
+ > $LogDir/llvm-gcc.install.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1
+ cd -
+}
+
+if [ "$do_checkout" = "yes" ]; then
+ export_sources
+fi
+
+(
+Flavors="Debug Release Release+Asserts"
+if [ "$do_64bit" = "yes" ]; then
+ Flavors="$Flavors Release-64"
+fi
+
+for Flavor in $Flavors ; do
+ echo ""
+ echo ""
+ echo "********************************************************************************"
+ echo " Release: $Release-rc$RC"
+ echo " Build: $Flavor"
+ echo " System Info: "
+ echo " `uname -a`"
+ echo "********************************************************************************"
+ echo ""
+
+ llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-rc$RC.obj
+ llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-rc$RC.install
+
+ llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-rc$RC.obj
+ llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-rc$RC.install
+
+ rm -rf $llvmCore_phase1_objdir
+ rm -rf $llvmCore_phase1_installdir
+ rm -rf $llvmCore_phase2_objdir
+ rm -rf $llvmCore_phase2_installdir
+
+ mkdir -p $llvmCore_phase1_objdir
+ mkdir -p $llvmCore_phase1_installdir
+ mkdir -p $llvmCore_phase2_objdir
+ mkdir -p $llvmCore_phase2_installdir
+
+ llvmgcc42_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmgcc42-$Release-rc$RC.obj
+ llvmgcc42_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmgcc42-$Release-rc$RC.install
+
+ llvmgcc42_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmgcc42-$Release-rc$RC.obj
+ llvmgcc42_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmgcc42-$Release-rc$RC.install
+
+ rm -rf $llvmgcc42_phase1_objdir
+ rm -rf $llvmgcc42_phase1_installdir
+ rm -rf $llvmgcc42_phase2_objdir
+ rm -rf $llvmgcc42_phase2_installdir
+
+ mkdir -p $llvmgcc42_phase1_objdir
+ mkdir -p $llvmgcc42_phase1_installdir
+ mkdir -p $llvmgcc42_phase2_objdir
+ mkdir -p $llvmgcc42_phase2_installdir
+
+ ############################################################################
+ # Phase 1: Build llvmCore and llvmgcc42
+ echo "# Phase 1: Building llvmCore"
+ configure_llvmCore 1 $Flavor \
+ $llvmCore_phase1_objdir $llvmCore_phase1_installdir \
+ $llvmgcc42_phase1_installdir
+ build_llvmCore 1 $Flavor \
+ $llvmCore_phase1_objdir
+
+ echo "# Phase 1: Building llvmgcc42"
+ configure_llvm_gcc 1 $Flavor \
+ $llvmgcc42_phase1_objdir $llvmgcc42_phase1_installdir \
+ $llvmCore_phase1_objdir
+ build_llvm_gcc 1 $Flavor \
+ $llvmgcc42_phase1_objdir $llvmgcc42_phase1_installdir
+
+ ############################################################################
+ # Phase 2: Build llvmCore with newly built llvmgcc42 from phase 1.
+ echo "# Phase 2: Building llvmCore"
+ configure_llvmCore 2 $Flavor \
+ $llvmCore_phase2_objdir $llvmCore_phase2_installdir \
+ $llvmgcc42_phase1_installdir
+ build_llvmCore 2 $Flavor \
+ $llvmCore_phase2_objdir
+
+ echo "# Phase 2: Building llvmgcc42"
+ configure_llvm_gcc 2 $Flavor \
+ $llvmgcc42_phase2_objdir $llvmgcc42_phase2_installdir \
+ $llvmCore_phase2_objdir
+ build_llvm_gcc 2 $Flavor \
+ $llvmgcc42_phase2_objdir $llvmgcc42_phase1_installdir
+
+ echo "# Testing - built with llvmgcc42"
+ test_llvmCore 2 $Flavor $llvmCore_phase2_objdir
+done
+) 2>&1 | tee $LogDir/testing.$Release-rc$RC.log
+
+# Woo hoo!
+echo "### Testing Finished ###"
+echo "### Logs: $LogDir"
+exit 0
diff --git a/utils/test_debuginfo.pl b/utils/test_debuginfo.pl
new file mode 100755
index 000000000000..fb61fb02616d
--- /dev/null
+++ b/utils/test_debuginfo.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+#
+# This script tests debugging information generated by a compiler.
+# Input arguments
+# - Input source program. Usually this source file is decorated using
+# special comments to communicate debugger commands.
+# - Executable file. This file is generated by the compiler.
+#
+# This perl script extracts debugger commands from input source program
+# comments in a script. A debugger is used to load the executable file
+# and run the script generated from source program comments. Finally,
+# the debugger output is checked, using FileCheck, to validate
+# debugging information.
+
+use File::Basename;
+
+my $testcase_file = $ARGV[0];
+my $executable_file = $ARGV[1];
+
+my $input_filename = basename $testcase_file;
+my $output_dir = dirname $executable_file;
+
+my $debugger_script_file = "$output_dir/$input_filename.debugger.script";
+my $output_file = "$output_dir/$input_filename.gdb.output";
+
+# Extract debugger commands from testcase. They are marked with DEBUGGER:
+# at the beginnign of a comment line.
+open(INPUT, $testcase_file);
+open(OUTPUT, ">$debugger_script_file");
+while(<INPUT>) {
+ my($line) = $_;
+ $i = index($line, "DEBUGGER:");
+ if ( $i >= 0) {
+ $l = length("DEBUGGER:");
+ $s = substr($line, $i + $l);
+ print OUTPUT "$s";
+ }
+}
+print OUTPUT "\n";
+print OUTPUT "quit\n";
+close(INPUT);
+close(OUTPUT);
+
+# setup debugger and debugger options to run a script.
+my $my_debugger = $ENV{'DEBUGGER'};
+if (!$my_debugger) {
+ $my_debugger = "gdb";
+}
+my $debugger_options = "-q -batch -n -x";
+
+# run debugger and capture output.
+system("$my_debugger $debugger_options $debugger_script_file $executable_file >& $output_file");
+
+# validate output.
+system("FileCheck", "-input-file", "$output_file", "$testcase_file");
+if ($?>>8 == 1) {
+ exit 1;
+}
+else {
+ exit 0;
+}
diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt
new file mode 100644
index 000000000000..29218bb37c71
--- /dev/null
+++ b/utils/unittest/CMakeLists.txt
@@ -0,0 +1,41 @@
+########################################################################
+# Experimental CMake build script for Google Test.
+#
+# Consider this a prototype. It will change drastically. For now,
+# this is only for people on the cutting edge.
+#
+# To run the tests for Google Test itself on Linux, use 'make test' or
+# ctest. You can select which tests to run using 'ctest -R regex'.
+# For more options, run 'ctest --help'.
+########################################################################
+#
+# Project-wide settings
+
+# Where gtest's .h files can be found.
+include_directories(
+ googletest/include
+ )
+
+if(WIN32)
+ add_definitions(-DGTEST_OS_WINDOWS=1)
+endif()
+
+if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
+ add_definitions("-Wno-variadic-macros")
+endif()
+
+set(LLVM_REQUIRES_RTTI 1)
+add_definitions( -DGTEST_HAS_RTTI=0 )
+
+add_llvm_library(gtest
+ googletest/gtest.cc
+ googletest/gtest-death-test.cc
+ googletest/gtest-filepath.cc
+ googletest/gtest-port.cc
+ googletest/gtest-test-part.cc
+ googletest/gtest-typed-test.cc
+ )
+
+add_llvm_library(gtest_main
+ UnitTestMain/TestMain.cpp
+ )
diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp
index d97dca872ad7..b35bae5abfb1 100644
--- a/utils/unittest/UnitTestMain/TestMain.cpp
+++ b/utils/unittest/UnitTestMain/TestMain.cpp
@@ -7,9 +7,36 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Config/config.h"
+#include "llvm/Support/Signals.h"
#include "gtest/gtest.h"
+
+#if defined(LLVM_ON_WIN32)
+# include <windows.h>
+# if defined(_MSC_VER)
+# include <crtdbg.h>
+# endif
+#endif
+
int main(int argc, char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
testing::InitGoogleTest(&argc, argv);
+
+# if defined(LLVM_ON_WIN32)
+ // Disable all of the possible ways Windows conspires to make automated
+ // testing impossible.
+ ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+# if defined(_MSC_VER)
+ ::_set_error_mode(_OUT_TO_STDERR);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+# endif
+# endif
+
return RUN_ALL_TESTS();
}
diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc
index aa2d5bb92509..51732afd4999 100644
--- a/utils/unittest/googletest/gtest.cc
+++ b/utils/unittest/googletest/gtest.cc
@@ -1964,8 +1964,8 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
} // namespace internal
-#if GTEST_OS_WINDOWS
-// We are on Windows.
+#if GTEST_HAS_SEH
+// We are on Windows with SEH.
// Adds an "exception thrown" fatal failure to the current test.
static void AddExceptionThrownFailure(DWORD exception_code,
@@ -1978,7 +1978,7 @@ static void AddExceptionThrownFailure(DWORD exception_code,
message.GetString());
}
-#endif // GTEST_OS_WINDOWS
+#endif // GTEST_HAS_SEH
// 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
@@ -2224,35 +2224,6 @@ 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
-
namespace internal {
// This method expands all parameterized tests registered with macros TEST_P
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
index 9683271e48f0..3d076eb44c78 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
@@ -403,7 +403,8 @@
// defining __GNUC__ and friends, but cannot compile GCC's tuple
// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
// Feature Pack download, which we cannot assume the user has.
-#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \
+#if (defined(__GNUC__) && !(defined(__CUDACC__) || defined(__clang__)) \
+ && (GTEST_GCC_VER_ >= 40000)) \
|| _MSC_VER >= 1600
#define GTEST_USE_OWN_TR1_TUPLE 0
#else
diff --git a/utils/valgrind/x86_64-pc-linux-gnu.supp b/utils/valgrind/x86_64-pc-linux-gnu.supp
index f5aae990f697..7b2dd4517daf 100644
--- a/utils/valgrind/x86_64-pc-linux-gnu.supp
+++ b/utils/valgrind/x86_64-pc-linux-gnu.supp
@@ -11,19 +11,19 @@
{
ADDRESS_IN_RANGE/Invalid read of size 4
Memcheck:Addr4
- obj:/usr/bin/python2.5
+ obj:/usr/bin/python*
}
{
ADDRESS_IN_RANGE/Invalid read of size 4
Memcheck:Value8
- obj:/usr/bin/python2.5
+ obj:/usr/bin/python*
}
{
ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
Memcheck:Cond
- obj:/usr/bin/python2.5
+ obj:/usr/bin/python*
}
{
@@ -42,5 +42,5 @@
We don't care if python leaks
Memcheck:Leak
fun:malloc
- obj:/usr/bin/python2.5
+ obj:/usr/bin/python*
}
diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim
index acebc20bc344..83e4c232dbe5 100644
--- a/utils/vim/llvm.vim
+++ b/utils/vim/llvm.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: llvm
" Maintainer: The LLVM team, http://llvm.org/
-" Version: $Revision: 112382 $
+" Version: $Revision: 114788 $
if version < 600
syntax clear
@@ -49,6 +49,7 @@ 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 ptx_kernel ptx_device
syn keyword llvmKeyword signext zeroext inreg sret nounwind noreturn
syn keyword llvmKeyword nocapture byval nest readnone readonly noalias
syn keyword llvmKeyword inlinehint noinline alwaysinline optsize ssp sspreq
diff --git a/utils/vim/vimrc b/utils/vim/vimrc
index 1f314c2e3f37..3f863d64bc49 100644
--- a/utils/vim/vimrc
+++ b/utils/vim/vimrc
@@ -1,5 +1,5 @@
" LLVM coding guidelines conformance for VIM
-" $Revision: 112982 $
+" $Revision: 117415 $
"
" Maintainer: The LLVM Team, http://llvm.org
" WARNING: Read before you source in all these commands and macros! Some
@@ -92,7 +92,7 @@ augroup END
"set incsearch
"set ruler
-" Clang code-completion support. This is highly experimental!
+" Clang code-completion support. This is somewhat experimental!
" A path to a clang executable.
let g:clang_path = "clang++"
@@ -216,5 +216,6 @@ function! ClangComplete(findstart, base)
return []
endfunction ClangComplete
-" Uncomment this to enable the highly-broken autocompletion support.
-"set omnifunc=ClangComplete
+" This to enables the somewhat-experimental clang-based
+" autocompletion support.
+set omnifunc=ClangComplete