aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorJush Lu <jush.msn@gmail.com>2011-03-09 19:39:16 +0800
committerJush Lu <jush.msn@gmail.com>2011-03-09 19:39:16 +0800
commitb5530586d68bd25831a6796b5d3199cb0769a35c (patch)
treefac4a03b53b6a64b0c00f433e4d8b3c9f2bc67cd /utils
parentb4e17c5bf4361bbdeced39aa071150d7fa9c3c10 (diff)
parentd01f50f42ce60207ed6d27fb1778e456d83be06c (diff)
downloadexternal_llvm-b5530586d68bd25831a6796b5d3199cb0769a35c.zip
external_llvm-b5530586d68bd25831a6796b5d3199cb0769a35c.tar.gz
external_llvm-b5530586d68bd25831a6796b5d3199cb0769a35c.tar.bz2
Merge upstream r127116
Diffstat (limited to 'utils')
-rwxr-xr-xutils/CollectDebugInfoUsingLLDB.py182
-rwxr-xr-xutils/CompareDebugInfo.py182
-rw-r--r--utils/FileCheck/CMakeLists.txt4
-rw-r--r--utils/FileCheck/FileCheck.cpp29
-rw-r--r--utils/FileCheck/Makefile6
-rw-r--r--utils/FileUpdate/CMakeLists.txt4
-rw-r--r--utils/FileUpdate/FileUpdate.cpp18
-rw-r--r--utils/FileUpdate/Makefile6
-rw-r--r--utils/KillTheDoctor/CMakeLists.txt5
-rw-r--r--utils/KillTheDoctor/KillTheDoctor.cpp50
-rw-r--r--utils/KillTheDoctor/system_error.cpp287
-rw-r--r--utils/KillTheDoctor/system_error.h903
-rw-r--r--utils/TableGen/ARMDecoderEmitter.cpp283
-rw-r--r--utils/TableGen/ARMDecoderEmitter.h2
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp910
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp255
-rw-r--r--utils/TableGen/AsmWriterEmitter.h1
-rw-r--r--utils/TableGen/CMakeLists.txt10
-rw-r--r--utils/TableGen/ClangASTNodesEmitter.h2
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp75
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp26
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp230
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.h31
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp13
-rw-r--r--utils/TableGen/CodeEmitterGen.h1
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp749
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h208
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp308
-rw-r--r--utils/TableGen/CodeGenInstruction.h18
-rw-r--r--utils/TableGen/CodeGenTarget.cpp13
-rw-r--r--utils/TableGen/CodeGenTarget.h9
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp32
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp42
-rw-r--r--utils/TableGen/DAGISelMatcher.h370
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp234
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp268
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp18
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp7
-rw-r--r--utils/TableGen/EDEmitter.cpp53
-rw-r--r--utils/TableGen/FastISelEmitter.cpp66
-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.cpp1
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.cpp14
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.h4
-rw-r--r--utils/TableGen/Makefile2
-rw-r--r--utils/TableGen/NeonEmitter.cpp1067
-rw-r--r--utils/TableGen/NeonEmitter.h78
-rw-r--r--utils/TableGen/Record.cpp112
-rw-r--r--utils/TableGen/Record.h26
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp24
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp2
-rw-r--r--utils/TableGen/TGLexer.cpp40
-rw-r--r--utils/TableGen/TGLexer.h4
-rw-r--r--utils/TableGen/TGParser.cpp95
-rw-r--r--utils/TableGen/TGParser.h7
-rw-r--r--utils/TableGen/TableGen.cpp39
-rw-r--r--utils/TableGen/X86ModRMFilters.h2
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp5
-rw-r--r--utils/TableGen/X86RecognizableInstr.h2
-rw-r--r--utils/Target/ARM/analyze-match-table.py61
-rw-r--r--utils/buildit/GNUmakefile6
-rwxr-xr-xutils/buildit/build_llvm15
-rw-r--r--utils/count/CMakeLists.txt2
-rw-r--r--utils/fpcmp/Makefile6
-rw-r--r--utils/lit/lit/LitConfig.py16
-rw-r--r--utils/lit/lit/TestFormats.py11
-rw-r--r--utils/lit/lit/TestRunner.py25
-rw-r--r--utils/lit/lit/TestingConfig.py2
-rw-r--r--utils/lit/lit/Util.py18
-rwxr-xr-x[-rw-r--r--]utils/llvm-lit/llvm-lit.in6
-rwxr-xr-xutils/llvmbuild749
-rw-r--r--utils/not/CMakeLists.txt4
-rw-r--r--utils/not/Makefile6
-rw-r--r--utils/not/not.cpp4
-rw-r--r--utils/unittest/UnitTestMain/Makefile2
-rw-r--r--utils/unittest/UnitTestMain/TestMain.cpp4
-rw-r--r--utils/unittest/googletest/include/gtest/gtest.h2
-rw-r--r--utils/valgrind/i386-pc-linux-gnu.supp8
-rw-r--r--utils/valgrind/x86_64-pc-linux-gnu.supp8
81 files changed, 6468 insertions, 3351 deletions
diff --git a/utils/CollectDebugInfoUsingLLDB.py b/utils/CollectDebugInfoUsingLLDB.py
new file mode 100755
index 0000000..4dbd19a
--- /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 0000000..2cd647e
--- /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 8fee03f..fa56f92 100644
--- a/utils/FileCheck/CMakeLists.txt
+++ b/utils/FileCheck/CMakeLists.txt
@@ -1,8 +1,8 @@
-add_executable(FileCheck
+add_llvm_utility(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 5e30c22..5d4cb0c 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>
@@ -488,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.
@@ -648,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);
diff --git a/utils/FileCheck/Makefile b/utils/FileCheck/Makefile
index f1af5b6..268b7bc 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 bacbd16..655aaec 100644
--- a/utils/FileUpdate/CMakeLists.txt
+++ b/utils/FileUpdate/CMakeLists.txt
@@ -1,8 +1,8 @@
-add_executable(FileUpdate
+add_llvm_utility(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 1c66c87..3ea1e4f 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/ToolOutputFile.h"
-#include "llvm/System/Signals.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 5b545c2..1e6c0a8 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/KillTheDoctor/CMakeLists.txt b/utils/KillTheDoctor/CMakeLists.txt
index 32e481c..37c2b7c 100644
--- a/utils/KillTheDoctor/CMakeLists.txt
+++ b/utils/KillTheDoctor/CMakeLists.txt
@@ -1,6 +1,5 @@
-add_executable(KillTheDoctor
+add_llvm_utility(KillTheDoctor
KillTheDoctor.cpp
- system_error.cpp
)
-target_link_libraries(KillTheDoctor LLVMSupport LLVMSystem)
+target_link_libraries(KillTheDoctor LLVMSupport)
diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp
index c0bf437..7a89dd3 100644
--- a/utils/KillTheDoctor/KillTheDoctor.cpp
+++ b/utils/KillTheDoctor/KillTheDoctor.cpp
@@ -16,14 +16,14 @@
// (and hopefully tells someone about it).
//
// This also provides another really hacky method to prevent assert dialog boxes
-// from poping up. When --no-user32 is passed, if any process loads user32.dll,
+// 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 sucessful termination, -1
+// 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.
@@ -41,8 +41,8 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/type_traits.h"
-#include "llvm/System/Signals.h"
-#include "system_error.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
@@ -164,10 +164,6 @@ namespace {
typedef ScopedHandle<ThreadHandle> ThreadScopedHandle;
typedef ScopedHandle<TokenHandle> TokenScopedHandle;
typedef ScopedHandle<FileHandle> FileScopedHandle;
-
- error_code get_windows_last_error() {
- return make_error_code(windows_error(::GetLastError()));
- }
}
static error_code GetFileNameFromHandle(HANDLE FileHandle,
@@ -181,7 +177,7 @@ static error_code GetFileNameFromHandle(HANDLE FileHandle,
Sucess = ::GetFileSizeEx(FileHandle, &FileSize);
if (!Sucess)
- return get_windows_last_error();
+ return windows_error(::GetLastError());
// Create a file mapping object.
FileMappingScopedHandle FileMapping(
@@ -193,14 +189,14 @@ static error_code GetFileNameFromHandle(HANDLE FileHandle,
NULL));
if (!FileMapping)
- return get_windows_last_error();
+ 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 get_windows_last_error();
+ return windows_error(::GetLastError());
Sucess = ::GetMappedFileNameA(::GetCurrentProcess(),
MappedFile,
@@ -208,7 +204,7 @@ static error_code GetFileNameFromHandle(HANDLE FileHandle,
array_lengthof(Filename) - 1);
if (!Sucess)
- return get_windows_last_error();
+ return windows_error(::GetLastError());
else {
Name = Filename;
return windows_error::success;
@@ -256,10 +252,10 @@ static std::string FindProgram(const std::string &Program, error_code &ec) {
PathName,
NULL);
if (length == 0)
- ec = get_windows_last_error();
+ ec = windows_error(::GetLastError());
else if (length > array_lengthof(PathName)) {
// This may have been the file, return with error.
- ec = error_code(windows_error::buffer_overflow);
+ ec = windows_error::buffer_overflow;
break;
} else {
// We found the path! Return it.
@@ -279,7 +275,7 @@ static error_code EnableDebugPrivileges() {
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&TokenHandle);
if (!success)
- return error_code(::GetLastError(), system_category());
+ return windows_error(::GetLastError());
TokenScopedHandle Token(TokenHandle);
TOKEN_PRIVILEGES TokenPrivileges;
@@ -289,7 +285,7 @@ static error_code EnableDebugPrivileges() {
SE_DEBUG_NAME,
&LocallyUniqueID);
if (!success)
- return error_code(::GetLastError(), system_category());
+ return windows_error(::GetLastError());
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Luid = LocallyUniqueID;
@@ -303,7 +299,7 @@ static error_code EnableDebugPrivileges() {
NULL);
// The value of success is basically useless. Either way we are just returning
// the value of ::GetLastError().
- return error_code(::GetLastError(), system_category());
+ return windows_error(::GetLastError());
}
static StringRef ExceptionCodeToString(DWORD ExceptionCode) {
@@ -387,7 +383,7 @@ int main(int argc, char **argv) {
StartupInfo.cb = sizeof(StartupInfo);
std::memset(&ProcessInfo, 0, sizeof(ProcessInfo));
- // Set error mode to not display any message boxes. The child process inherets
+ // 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);
@@ -404,7 +400,7 @@ int main(int argc, char **argv) {
&ProcessInfo);
if (!success) {
errs() << ToolName << ": Failed to run program: '" << ProgramToRun
- << "': " << error_code(::GetLastError(), system_category()).message()
+ << "': " << error_code(windows_error(::GetLastError())).message()
<< '\n';
return -1;
}
@@ -432,7 +428,7 @@ int main(int argc, char **argv) {
&KernelTime,
&UserTime);
if (!success) {
- ec = error_code(::GetLastError(), system_category());
+ ec = windows_error(::GetLastError());
errs() << ToolName << ": Failed to get process times: "
<< ec.message() << '\n';
@@ -442,7 +438,7 @@ int main(int argc, char **argv) {
a.HighPart = KernelTime.dwHighDateTime;
b.LowPart = UserTime.dwLowDateTime;
b.HighPart = UserTime.dwHighDateTime;
- // Convert 100-nanosecond units to miliseconds.
+ // 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.
@@ -467,9 +463,9 @@ int main(int argc, char **argv) {
success = WaitForDebugEvent(&DebugEvent, TimeLeft);
if (!success) {
- ec = error_code(::GetLastError(), system_category());
+ ec = windows_error(::GetLastError());
- if (ec == error_condition(errc::timed_out)) {
+ if (ec == errc::timed_out) {
errs() << ToolName << ": Process timed out.\n";
::TerminateProcess(ProcessInfo.hProcess, -1);
// Otherwise other stuff starts failing...
@@ -494,7 +490,7 @@ int main(int argc, char **argv) {
if (TraceExecution)
errs() << ToolName << ": Debug Event: EXIT_PROCESS_DEBUG_EVENT\n";
- // If this is the process we origionally created, exit with its exit
+ // If this is the process we originally created, exit with its exit
// code.
if (DebugEvent.dwProcessId == ProcessInfo.dwProcessId)
return DebugEvent.u.ExitProcess.dwExitCode;
@@ -527,14 +523,14 @@ int main(int argc, char **argv) {
errs().indent(ToolName.size()) << ": DLL Name : " << DLLName << '\n';
}
- if (NoUser32 && sys::Path(DLLName).getBasename() == "user32") {
+ 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 poping up.\n";
+ "program to prevent message box from popping up.\n";
dwContinueStatus = DBG_CONTINUE;
::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1);
return -1;
@@ -586,7 +582,7 @@ int main(int argc, char **argv) {
DebugEvent.dwThreadId,
dwContinueStatus);
if (!success) {
- ec = error_code(::GetLastError(), system_category());
+ ec = windows_error(::GetLastError());
errs() << ToolName << ": Failed to continue debugging program: '"
<< ProgramToRun << "': " << ec.message() << '\n';
return -1;
diff --git a/utils/KillTheDoctor/system_error.cpp b/utils/KillTheDoctor/system_error.cpp
deleted file mode 100644
index 0e78fb3..0000000
--- a/utils/KillTheDoctor/system_error.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-//===---------------------- system_error.cpp ------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This was lifted from libc++ and modified for C++03.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Config/config.h"
-#include "system_error.h"
-#include <string>
-#include <cstring>
-
-namespace llvm {
-
-// class error_category
-
-error_category::error_category() {
-}
-
-error_category::~error_category() {
-}
-
-error_condition
-error_category::default_error_condition(int ev) const {
- return error_condition(ev, *this);
-}
-
-bool
-error_category::equivalent(int code, const error_condition& condition) const {
- return default_error_condition(code) == condition;
-}
-
-bool
-error_category::equivalent(const error_code& code, int condition) const {
- return *this == code.category() && code.value() == condition;
-}
-
-std::string
-_do_message::message(int ev) const {
- return std::string(std::strerror(ev));
-}
-
-class _generic_error_category : public _do_message {
-public:
- virtual const char* name() const;
- virtual std::string message(int ev) const;
-};
-
-const char*
-_generic_error_category::name() const {
- return "generic";
-}
-
-std::string
-_generic_error_category::message(int ev) const {
-#ifdef ELAST
- if (ev > ELAST)
- return std::string("unspecified generic_category error");
-#endif // ELAST
- return _do_message::message(ev);
-}
-
-const error_category&
-generic_category() {
- static _generic_error_category s;
- return s;
-}
-
-class _system_error_category : public _do_message {
-public:
- virtual const char* name() const;
- virtual std::string message(int ev) const;
- virtual error_condition default_error_condition(int ev) const;
-};
-
-const char*
-_system_error_category::name() const {
- return "system";
-}
-
-// std::string _system_error_category::message(int ev) const {
-// Is in Platform/system_error.inc
-
-// error_condition _system_error_category::default_error_condition(int ev) const
-// Is in Platform/system_error.inc
-
-const error_category&
-system_category() {
- static _system_error_category s;
- return s;
-}
-
-// error_condition
-
-std::string
-error_condition::message() const {
- return _cat_->message(_val_);
-}
-
-// error_code
-
-std::string
-error_code::message() const {
- return _cat_->message(_val_);
-}
-
-// system_error
-
-std::string
-system_error::_init(const error_code& ec, std::string what_arg) {
- if (ec)
- {
- if (!what_arg.empty())
- what_arg += ": ";
- what_arg += ec.message();
- }
- return what_arg;
-}
-
-system_error::system_error(error_code ec, const std::string& what_arg)
- : runtime_error(_init(ec, what_arg)), _ec_(ec) {
-}
-
-system_error::system_error(error_code ec, const char* what_arg)
- : runtime_error(_init(ec, what_arg)), _ec_(ec) {
-}
-
-system_error::system_error(error_code ec)
- : runtime_error(_init(ec, "")), _ec_(ec) {
-}
-
-system_error::system_error(int ev, const error_category& ecat,
- const std::string& what_arg)
- : runtime_error(_init(error_code(ev, ecat), what_arg))
- , _ec_(error_code(ev, ecat)) {
-}
-
-system_error::system_error(int ev, const error_category& ecat,
- const char* what_arg)
- : runtime_error(_init(error_code(ev, ecat), what_arg))
- , _ec_(error_code(ev, ecat)) {
-}
-
-system_error::system_error(int ev, const error_category& ecat)
- : runtime_error(_init(error_code(ev, ecat), "")), _ec_(error_code(ev, ecat)) {
-}
-
-system_error::~system_error() throw() {
-}
-
-void
-_throw_system_error(int ev, const char* what_arg) {
- throw system_error(error_code(ev, system_category()), what_arg);
-}
-
-} // end namespace llvm
-
-#ifdef LLVM_ON_WIN32
-#include <Windows.h>
-#include <WinError.h>
-
-namespace llvm {
-
-std::string
-_system_error_category::message(int ev) const {
- LPVOID lpMsgBuf = 0;
- DWORD retval = ::FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- ev,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPSTR) &lpMsgBuf,
- 0,
- NULL);
- if (retval == 0) {
- ::LocalFree(lpMsgBuf);
- return std::string("Unknown error");
- }
-
- std::string str( static_cast<LPCSTR>(lpMsgBuf) );
- ::LocalFree(lpMsgBuf);
-
- while (str.size()
- && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r'))
- str.erase( str.size()-1 );
- if (str.size() && str[str.size()-1] == '.')
- str.erase( str.size()-1 );
- return str;
-}
-
-error_condition
-_system_error_category::default_error_condition(int ev) const {
- switch (ev)
- {
- case 0: return make_error_condition(errc::success);
- // Windows system -> posix_errno decode table ---------------------------//
- // see WinError.h comments for descriptions of errors
- case ERROR_ACCESS_DENIED: return make_error_condition(errc::permission_denied);
- case ERROR_ALREADY_EXISTS: return make_error_condition(errc::file_exists);
- case ERROR_BAD_UNIT: return make_error_condition(errc::no_such_device);
- case ERROR_BUFFER_OVERFLOW: return make_error_condition(errc::filename_too_long);
- case ERROR_BUSY: return make_error_condition(errc::device_or_resource_busy);
- case ERROR_BUSY_DRIVE: return make_error_condition(errc::device_or_resource_busy);
- case ERROR_CANNOT_MAKE: return make_error_condition(errc::permission_denied);
- case ERROR_CANTOPEN: return make_error_condition(errc::io_error);
- case ERROR_CANTREAD: return make_error_condition(errc::io_error);
- case ERROR_CANTWRITE: return make_error_condition(errc::io_error);
- case ERROR_CURRENT_DIRECTORY: return make_error_condition(errc::permission_denied);
- case ERROR_DEV_NOT_EXIST: return make_error_condition(errc::no_such_device);
- case ERROR_DEVICE_IN_USE: return make_error_condition(errc::device_or_resource_busy);
- case ERROR_DIR_NOT_EMPTY: return make_error_condition(errc::directory_not_empty);
- case ERROR_DIRECTORY: return make_error_condition(errc::invalid_argument);
- case ERROR_DISK_FULL: return make_error_condition(errc::no_space_on_device);
- case ERROR_FILE_EXISTS: return make_error_condition(errc::file_exists);
- case ERROR_FILE_NOT_FOUND: return make_error_condition(errc::no_such_file_or_directory);
- case ERROR_HANDLE_DISK_FULL: return make_error_condition(errc::no_space_on_device);
- case ERROR_INVALID_ACCESS: return make_error_condition(errc::permission_denied);
- case ERROR_INVALID_DRIVE: return make_error_condition(errc::no_such_device);
- case ERROR_INVALID_FUNCTION: return make_error_condition(errc::function_not_supported);
- case ERROR_INVALID_HANDLE: return make_error_condition(errc::invalid_argument);
- case ERROR_INVALID_NAME: return make_error_condition(errc::invalid_argument);
- case ERROR_LOCK_VIOLATION: return make_error_condition(errc::no_lock_available);
- case ERROR_LOCKED: return make_error_condition(errc::no_lock_available);
- case ERROR_NEGATIVE_SEEK: return make_error_condition(errc::invalid_argument);
- case ERROR_NOACCESS: return make_error_condition(errc::permission_denied);
- case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition(errc::not_enough_memory);
- case ERROR_NOT_READY: return make_error_condition(errc::resource_unavailable_try_again);
- case ERROR_NOT_SAME_DEVICE: return make_error_condition(errc::cross_device_link);
- case ERROR_OPEN_FAILED: return make_error_condition(errc::io_error);
- case ERROR_OPEN_FILES: return make_error_condition(errc::device_or_resource_busy);
- case ERROR_OPERATION_ABORTED: return make_error_condition(errc::operation_canceled);
- case ERROR_OUTOFMEMORY: return make_error_condition(errc::not_enough_memory);
- case ERROR_PATH_NOT_FOUND: return make_error_condition(errc::no_such_file_or_directory);
- case ERROR_READ_FAULT: return make_error_condition(errc::io_error);
- case ERROR_RETRY: return make_error_condition(errc::resource_unavailable_try_again);
- case ERROR_SEEK: return make_error_condition(errc::io_error);
- case ERROR_SHARING_VIOLATION: return make_error_condition(errc::permission_denied);
- case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition(errc::too_many_files_open);
- case ERROR_WRITE_FAULT: return make_error_condition(errc::io_error);
- case ERROR_WRITE_PROTECT: return make_error_condition(errc::permission_denied);
- case ERROR_SEM_TIMEOUT: return make_error_condition(errc::timed_out);
- case WSAEACCES: return make_error_condition(errc::permission_denied);
- case WSAEADDRINUSE: return make_error_condition(errc::address_in_use);
- case WSAEADDRNOTAVAIL: return make_error_condition(errc::address_not_available);
- case WSAEAFNOSUPPORT: return make_error_condition(errc::address_family_not_supported);
- case WSAEALREADY: return make_error_condition(errc::connection_already_in_progress);
- case WSAEBADF: return make_error_condition(errc::bad_file_descriptor);
- case WSAECONNABORTED: return make_error_condition(errc::connection_aborted);
- case WSAECONNREFUSED: return make_error_condition(errc::connection_refused);
- case WSAECONNRESET: return make_error_condition(errc::connection_reset);
- case WSAEDESTADDRREQ: return make_error_condition(errc::destination_address_required);
- case WSAEFAULT: return make_error_condition(errc::bad_address);
- case WSAEHOSTUNREACH: return make_error_condition(errc::host_unreachable);
- case WSAEINPROGRESS: return make_error_condition(errc::operation_in_progress);
- case WSAEINTR: return make_error_condition(errc::interrupted);
- case WSAEINVAL: return make_error_condition(errc::invalid_argument);
- case WSAEISCONN: return make_error_condition(errc::already_connected);
- case WSAEMFILE: return make_error_condition(errc::too_many_files_open);
- case WSAEMSGSIZE: return make_error_condition(errc::message_size);
- case WSAENAMETOOLONG: return make_error_condition(errc::filename_too_long);
- case WSAENETDOWN: return make_error_condition(errc::network_down);
- case WSAENETRESET: return make_error_condition(errc::network_reset);
- case WSAENETUNREACH: return make_error_condition(errc::network_unreachable);
- case WSAENOBUFS: return make_error_condition(errc::no_buffer_space);
- case WSAENOPROTOOPT: return make_error_condition(errc::no_protocol_option);
- case WSAENOTCONN: return make_error_condition(errc::not_connected);
- case WSAENOTSOCK: return make_error_condition(errc::not_a_socket);
- case WSAEOPNOTSUPP: return make_error_condition(errc::operation_not_supported);
- case WSAEPROTONOSUPPORT: return make_error_condition(errc::protocol_not_supported);
- case WSAEPROTOTYPE: return make_error_condition(errc::wrong_protocol_type);
- case WSAETIMEDOUT: return make_error_condition(errc::timed_out);
- case WSAEWOULDBLOCK: return make_error_condition(errc::operation_would_block);
- default: return error_condition(ev, system_category());
- }
-}
-
-} // end namespace llvm
-
-#endif // LLVM_ON_WIN32
diff --git a/utils/KillTheDoctor/system_error.h b/utils/KillTheDoctor/system_error.h
deleted file mode 100644
index 55faa1b..0000000
--- a/utils/KillTheDoctor/system_error.h
+++ /dev/null
@@ -1,903 +0,0 @@
-//===---------------------------- system_error ----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This was lifted from libc++ and modified for C++03.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SYSTEM_SYSTEM_ERROR_H
-#define LLVM_SYSTEM_SYSTEM_ERROR_H
-
-/*
- system_error synopsis
-
-namespace std
-{
-
-class error_category
-{
-public:
- virtual ~error_category();
-
- error_category(const error_category&) = delete;
- error_category& operator=(const error_category&) = delete;
-
- virtual const char* name() const = 0;
- virtual error_condition default_error_condition(int ev) const;
- virtual bool equivalent(int code, const error_condition& condition) const;
- virtual bool equivalent(const error_code& code, int condition) const;
- virtual std::string message(int ev) const = 0;
-
- bool operator==(const error_category& rhs) const;
- bool operator!=(const error_category& rhs) const;
- bool operator<(const error_category& rhs) const;
-};
-
-const error_category& generic_category();
-const error_category& system_category();
-
-template <class T> struct is_error_code_enum
- : public false_type {};
-
-template <class T> struct is_error_condition_enum
- : public false_type {};
-
-class error_code
-{
-public:
- // constructors:
- error_code();
- error_code(int val, const error_category& cat);
- template <class ErrorCodeEnum>
- error_code(ErrorCodeEnum e);
-
- // modifiers:
- void assign(int val, const error_category& cat);
- template <class ErrorCodeEnum>
- error_code& operator=(ErrorCodeEnum e);
- void clear();
-
- // observers:
- int value() const;
- const error_category& category() const;
- error_condition default_error_condition() const;
- std::string message() const;
- explicit operator bool() const;
-};
-
-// non-member functions:
-bool operator<(const error_code& lhs, const error_code& rhs);
-template <class charT, class traits>
- basic_ostream<charT,traits>&
- operator<<(basic_ostream<charT,traits>& os, const error_code& ec);
-
-class error_condition
-{
-public:
- // constructors:
- error_condition();
- error_condition(int val, const error_category& cat);
- template <class ErrorConditionEnum>
- error_condition(ErrorConditionEnum e);
-
- // modifiers:
- void assign(int val, const error_category& cat);
- template <class ErrorConditionEnum>
- error_condition& operator=(ErrorConditionEnum e);
- void clear();
-
- // observers:
- int value() const;
- const error_category& category() const;
- std::string message() const;
- explicit operator bool() const;
-};
-
-bool operator<(const error_condition& lhs, const error_condition& rhs);
-
-class system_error
- : public runtime_error
-{
-public:
- system_error(error_code ec, const std::string& what_arg);
- system_error(error_code ec, const char* what_arg);
- system_error(error_code ec);
- system_error(int ev, const error_category& ecat, const std::string& what_arg);
- system_error(int ev, const error_category& ecat, const char* what_arg);
- system_error(int ev, const error_category& ecat);
-
- const error_code& code() const throw();
- const char* what() const throw();
-};
-
-enum class errc
-{
- address_family_not_supported, // EAFNOSUPPORT
- address_in_use, // EADDRINUSE
- address_not_available, // EADDRNOTAVAIL
- already_connected, // EISCONN
- argument_list_too_long, // E2BIG
- argument_out_of_domain, // EDOM
- bad_address, // EFAULT
- bad_file_descriptor, // EBADF
- bad_message, // EBADMSG
- broken_pipe, // EPIPE
- connection_aborted, // ECONNABORTED
- connection_already_in_progress, // EALREADY
- connection_refused, // ECONNREFUSED
- connection_reset, // ECONNRESET
- cross_device_link, // EXDEV
- destination_address_required, // EDESTADDRREQ
- device_or_resource_busy, // EBUSY
- directory_not_empty, // ENOTEMPTY
- executable_format_error, // ENOEXEC
- file_exists, // EEXIST
- file_too_large, // EFBIG
- filename_too_long, // ENAMETOOLONG
- function_not_supported, // ENOSYS
- host_unreachable, // EHOSTUNREACH
- identifier_removed, // EIDRM
- illegal_byte_sequence, // EILSEQ
- inappropriate_io_control_operation, // ENOTTY
- interrupted, // EINTR
- invalid_argument, // EINVAL
- invalid_seek, // ESPIPE
- io_error, // EIO
- is_a_directory, // EISDIR
- message_size, // EMSGSIZE
- network_down, // ENETDOWN
- network_reset, // ENETRESET
- network_unreachable, // ENETUNREACH
- no_buffer_space, // ENOBUFS
- no_child_process, // ECHILD
- no_link, // ENOLINK
- no_lock_available, // ENOLCK
- no_message_available, // ENODATA
- no_message, // ENOMSG
- no_protocol_option, // ENOPROTOOPT
- no_space_on_device, // ENOSPC
- no_stream_resources, // ENOSR
- no_such_device_or_address, // ENXIO
- no_such_device, // ENODEV
- no_such_file_or_directory, // ENOENT
- no_such_process, // ESRCH
- not_a_directory, // ENOTDIR
- not_a_socket, // ENOTSOCK
- not_a_stream, // ENOSTR
- not_connected, // ENOTCONN
- not_enough_memory, // ENOMEM
- not_supported, // ENOTSUP
- operation_canceled, // ECANCELED
- operation_in_progress, // EINPROGRESS
- operation_not_permitted, // EPERM
- operation_not_supported, // EOPNOTSUPP
- operation_would_block, // EWOULDBLOCK
- owner_dead, // EOWNERDEAD
- permission_denied, // EACCES
- protocol_error, // EPROTO
- protocol_not_supported, // EPROTONOSUPPORT
- read_only_file_system, // EROFS
- resource_deadlock_would_occur, // EDEADLK
- resource_unavailable_try_again, // EAGAIN
- result_out_of_range, // ERANGE
- state_not_recoverable, // ENOTRECOVERABLE
- stream_timeout, // ETIME
- text_file_busy, // ETXTBSY
- timed_out, // ETIMEDOUT
- too_many_files_open_in_system, // ENFILE
- too_many_files_open, // EMFILE
- too_many_links, // EMLINK
- too_many_symbolic_link_levels, // ELOOP
- value_too_large, // EOVERFLOW
- wrong_protocol_type // EPROTOTYPE
-};
-
-template <> struct is_error_condition_enum<errc> : true_type { }
-
-error_code make_error_code(errc e);
-error_condition make_error_condition(errc e);
-
-// Comparison operators:
-bool operator==(const error_code& lhs, const error_code& rhs);
-bool operator==(const error_code& lhs, const error_condition& rhs);
-bool operator==(const error_condition& lhs, const error_code& rhs);
-bool operator==(const error_condition& lhs, const error_condition& rhs);
-bool operator!=(const error_code& lhs, const error_code& rhs);
-bool operator!=(const error_code& lhs, const error_condition& rhs);
-bool operator!=(const error_condition& lhs, const error_code& rhs);
-bool operator!=(const error_condition& lhs, const error_condition& rhs);
-
-template <> struct hash<std::error_code>;
-
-} // std
-
-*/
-
-#include "llvm/Config/config.h"
-#include "llvm/Support/type_traits.h"
-#include <cerrno>
-#include <string>
-
-#ifdef LLVM_ON_WIN32
- // VS 2008 needs this for some of the defines below.
-# include <WinSock2.h>
-
- // The following numbers were taken from VS2010.
-# ifndef EAFNOSUPPORT
-# define EAFNOSUPPORT WSAEAFNOSUPPORT
-# endif
-# ifndef EADDRINUSE
-# define EADDRINUSE WSAEADDRINUSE
-# endif
-# ifndef EADDRNOTAVAIL
-# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
-# endif
-# ifndef EISCONN
-# define EISCONN WSAEISCONN
-# endif
-# ifndef E2BIG
-# define E2BIG WSAE2BIG
-# endif
-# ifndef EDOM
-# define EDOM WSAEDOM
-# endif
-# ifndef EFAULT
-# define EFAULT WSAEFAULT
-# endif
-# ifndef EBADF
-# define EBADF WSAEBADF
-# endif
-# ifndef EBADMSG
-# define EBADMSG 104
-# endif
-# ifndef EPIPE
-# define EPIPE WSAEPIPE
-# endif
-# ifndef ECONNABORTED
-# define ECONNABORTED WSAECONNABORTED
-# endif
-# ifndef EALREADY
-# define EALREADY WSAEALREADY
-# endif
-# ifndef ECONNREFUSED
-# define ECONNREFUSED WSAECONNREFUSED
-# endif
-# ifndef ECONNRESET
-# define ECONNRESET WSAECONNRESET
-# endif
-# ifndef EXDEV
-# define EXDEV WSAEXDEV
-# endif
-# ifndef EDESTADDRREQ
-# define EDESTADDRREQ WSAEDESTADDRREQ
-# endif
-# ifndef EBUSY
-# define EBUSY WSAEBUSY
-# endif
-# ifndef ENOTEMPTY
-# define ENOTEMPTY WSAENOTEMPTY
-# endif
-# ifndef ENOEXEC
-# define ENOEXEC WSAENOEXEC
-# endif
-# ifndef EEXIST
-# define EEXIST WSAEEXIST
-# endif
-# ifndef EFBIG
-# define EFBIG WSAEFBIG
-# endif
-# ifndef ENAMETOOLONG
-# define ENAMETOOLONG WSAENAMETOOLONG
-# endif
-# ifndef ENOSYS
-# define ENOSYS WSAENOSYS
-# endif
-# ifndef EHOSTUNREACH
-# define EHOSTUNREACH WSAEHOSTUNREACH
-# endif
-# ifndef EIDRM
-# define EIDRM 111
-# endif
-# ifndef EILSEQ
-# define EILSEQ WSAEILSEQ
-# endif
-# ifndef ENOTTY
-# define ENOTTY WSAENOTTY
-# endif
-# ifndef EINTR
-# define EINTR WSAEINTR
-# endif
-# ifndef EINVAL
-# define EINVAL WSAEINVAL
-# endif
-# ifndef ESPIPE
-# define ESPIPE WSAESPIPE
-# endif
-# ifndef EIO
-# define EIO WSAEIO
-# endif
-# ifndef EISDIR
-# define EISDIR WSAEISDIR
-# endif
-# ifndef EMSGSIZE
-# define EMSGSIZE WSAEMSGSIZE
-# endif
-# ifndef ENETDOWN
-# define ENETDOWN WSAENETDOWN
-# endif
-# ifndef ENETRESET
-# define ENETRESET WSAENETRESET
-# endif
-# ifndef ENETUNREACH
-# define ENETUNREACH WSAENETUNREACH
-# endif
-# ifndef ENOBUFS
-# define ENOBUFS WSAENOBUFS
-# endif
-# ifndef ECHILD
-# define ECHILD WSAECHILD
-# endif
-# ifndef ENOLINK
-# define ENOLINK 121
-# endif
-# ifndef ENOLCK
-# define ENOLCK WSAENOLCK
-# endif
-# ifndef ENODATA
-# define ENODATA 120
-# endif
-# ifndef ENOMSG
-# define ENOMSG 122
-# endif
-# ifndef ENOPROTOOPT
-# define ENOPROTOOPT WSAENOPROTOOPT
-# endif
-# ifndef ENOSPC
-# define ENOSPC WSAENOSPC
-# endif
-# ifndef ENOSR
-# define ENOSR 124
-# endif
-# ifndef ENXIO
-# define ENXIO WSAENXIO
-# endif
-# ifndef ENODEV
-# define ENODEV WSAENODEV
-# endif
-# ifndef ENOENT
-# define ENOENT WSAENOENT
-# endif
-# ifndef ESRCH
-# define ESRCH WSAESRCH
-# endif
-# ifndef ENOTDIR
-# define ENOTDIR WSAENOTDIR
-# endif
-# ifndef ENOTSOCK
-# define ENOTSOCK WSAENOTSOCK
-# endif
-# ifndef ENOSTR
-# define ENOSTR 125
-# endif
-# ifndef ENOTCONN
-# define ENOTCONN WSAENOTCONN
-# endif
-# ifndef ENOMEM
-# define ENOMEM WSAENOMEM
-# endif
-# ifndef ENOTSUP
-# define ENOTSUP 129
-# endif
-# ifndef ECANCELED
-# define ECANCELED 105
-# endif
-# ifndef EINPROGRESS
-# define EINPROGRESS WSAEINPROGRESS
-# endif
-# ifndef EPERM
-# define EPERM WSAEPERM
-# endif
-# ifndef EOPNOTSUPP
-# define EOPNOTSUPP WSAEOPNOTSUPP
-# endif
-# ifndef EWOULDBLOCK
-# define EWOULDBLOCK WSAEWOULDBLOCK
-# endif
-# ifndef EOWNERDEAD
-# define EOWNERDEAD 133
-# endif
-# ifndef EACCES
-# define EACCES WSAEACCES
-# endif
-# ifndef EPROTO
-# define EPROTO 134
-# endif
-# ifndef EPROTONOSUPPORT
-# define EPROTONOSUPPORT WSAEPROTONOSUPPORT
-# endif
-# ifndef EROFS
-# define EROFS WSAEROFS
-# endif
-# ifndef EDEADLK
-# define EDEADLK WSAEDEADLK
-# endif
-# ifndef EAGAIN
-# define EAGAIN WSAEAGAIN
-# endif
-# ifndef ERANGE
-# define ERANGE WSAERANGE
-# endif
-# ifndef ENOTRECOVERABLE
-# define ENOTRECOVERABLE 127
-# endif
-# ifndef ETIME
-# define ETIME 137
-# endif
-# ifndef ETXTBSY
-# define ETXTBSY 139
-# endif
-# ifndef ETIMEDOUT
-# define ETIMEDOUT WSAETIMEDOUT
-# endif
-# ifndef ENFILE
-# define ENFILE WSAENFILE
-# endif
-# ifndef EMFILE
-# define EMFILE WSAEMFILE
-# endif
-# ifndef EMLINK
-# define EMLINK WSAEMLINK
-# endif
-# ifndef ELOOP
-# define ELOOP WSAELOOP
-# endif
-# ifndef EOVERFLOW
-# define EOVERFLOW 132
-# endif
-# ifndef EPROTOTYPE
-# define EPROTOTYPE WSAEPROTOTYPE
-# endif
-#endif
-
-namespace llvm {
-
-template <class T, T v>
-struct integral_constant {
- typedef T value_type;
- static const value_type value = v;
- typedef integral_constant<T,v> type;
- operator value_type() { return value; }
-};
-
-typedef integral_constant<bool, true> true_type;
-typedef integral_constant<bool, false> false_type;
-
-// is_error_code_enum
-
-template <class Tp> struct is_error_code_enum : public false_type {};
-
-// is_error_condition_enum
-
-template <class Tp> struct is_error_condition_enum : public false_type {};
-
-// Some error codes are not present on all platforms, so we provide equivalents
-// for them:
-
-//enum class errc
-struct errc {
-enum _ {
- success = 0,
- address_family_not_supported = EAFNOSUPPORT,
- address_in_use = EADDRINUSE,
- address_not_available = EADDRNOTAVAIL,
- already_connected = EISCONN,
- argument_list_too_long = E2BIG,
- argument_out_of_domain = EDOM,
- bad_address = EFAULT,
- bad_file_descriptor = EBADF,
- bad_message = EBADMSG,
- broken_pipe = EPIPE,
- connection_aborted = ECONNABORTED,
- connection_already_in_progress = EALREADY,
- connection_refused = ECONNREFUSED,
- connection_reset = ECONNRESET,
- cross_device_link = EXDEV,
- destination_address_required = EDESTADDRREQ,
- device_or_resource_busy = EBUSY,
- directory_not_empty = ENOTEMPTY,
- executable_format_error = ENOEXEC,
- file_exists = EEXIST,
- file_too_large = EFBIG,
- filename_too_long = ENAMETOOLONG,
- function_not_supported = ENOSYS,
- host_unreachable = EHOSTUNREACH,
- identifier_removed = EIDRM,
- illegal_byte_sequence = EILSEQ,
- inappropriate_io_control_operation = ENOTTY,
- interrupted = EINTR,
- invalid_argument = EINVAL,
- invalid_seek = ESPIPE,
- io_error = EIO,
- is_a_directory = EISDIR,
- message_size = EMSGSIZE,
- network_down = ENETDOWN,
- network_reset = ENETRESET,
- network_unreachable = ENETUNREACH,
- no_buffer_space = ENOBUFS,
- no_child_process = ECHILD,
- no_link = ENOLINK,
- no_lock_available = ENOLCK,
-#ifdef ENODATA
- no_message_available = ENODATA,
-#else
- no_message_available = ENOMSG,
-#endif
- no_message = ENOMSG,
- no_protocol_option = ENOPROTOOPT,
- no_space_on_device = ENOSPC,
-#ifdef ENOSR
- no_stream_resources = ENOSR,
-#else
- no_stream_resources = ENOMEM,
-#endif
- no_such_device_or_address = ENXIO,
- no_such_device = ENODEV,
- no_such_file_or_directory = ENOENT,
- no_such_process = ESRCH,
- not_a_directory = ENOTDIR,
- not_a_socket = ENOTSOCK,
-#ifdef ENOSTR
- not_a_stream = ENOSTR,
-#else
- not_a_stream = EINVAL,
-#endif
- not_connected = ENOTCONN,
- not_enough_memory = ENOMEM,
- not_supported = ENOTSUP,
- operation_canceled = ECANCELED,
- operation_in_progress = EINPROGRESS,
- operation_not_permitted = EPERM,
- operation_not_supported = EOPNOTSUPP,
- operation_would_block = EWOULDBLOCK,
- owner_dead = EOWNERDEAD,
- permission_denied = EACCES,
- protocol_error = EPROTO,
- protocol_not_supported = EPROTONOSUPPORT,
- read_only_file_system = EROFS,
- resource_deadlock_would_occur = EDEADLK,
- resource_unavailable_try_again = EAGAIN,
- result_out_of_range = ERANGE,
- state_not_recoverable = ENOTRECOVERABLE,
-#ifdef ETIME
- stream_timeout = ETIME,
-#else
- stream_timeout = ETIMEDOUT,
-#endif
- text_file_busy = ETXTBSY,
- timed_out = ETIMEDOUT,
- too_many_files_open_in_system = ENFILE,
- too_many_files_open = EMFILE,
- too_many_links = EMLINK,
- too_many_symbolic_link_levels = ELOOP,
- value_too_large = EOVERFLOW,
- wrong_protocol_type = EPROTOTYPE
-};
-
- _ v_;
-
- errc(_ v) : v_(v) {}
- operator int() const {return v_;}
-};
-
-template <> struct is_error_condition_enum<errc> : true_type { };
-
-template <> struct is_error_condition_enum<errc::_> : true_type { };
-
-class error_condition;
-class error_code;
-
-// class error_category
-
-class _do_message;
-
-class error_category
-{
-public:
- virtual ~error_category();
-
-private:
- error_category();
- error_category(const error_category&);// = delete;
- error_category& operator=(const error_category&);// = delete;
-
-public:
- virtual const char* name() const = 0;
- virtual error_condition default_error_condition(int _ev) const;
- virtual bool equivalent(int _code, const error_condition& _condition) const;
- virtual bool equivalent(const error_code& _code, int _condition) const;
- virtual std::string message(int _ev) const = 0;
-
- bool operator==(const error_category& _rhs) const {return this == &_rhs;}
-
- bool operator!=(const error_category& _rhs) const {return !(*this == _rhs);}
-
- bool operator< (const error_category& _rhs) const {return this < &_rhs;}
-
- friend class _do_message;
-};
-
-class _do_message : public error_category
-{
-public:
- virtual std::string message(int ev) const;
-};
-
-const error_category& generic_category();
-const error_category& system_category();
-
-class error_condition
-{
- int _val_;
- const error_category* _cat_;
-public:
- error_condition() : _val_(0), _cat_(&generic_category()) {}
-
- error_condition(int _val, const error_category& _cat)
- : _val_(_val), _cat_(&_cat) {}
-
- template <class E>
- error_condition(E _e, typename enable_if_c<
- is_error_condition_enum<E>::value
- >::type* = 0)
- {*this = make_error_condition(_e);}
-
- void assign(int _val, const error_category& _cat) {
- _val_ = _val;
- _cat_ = &_cat;
- }
-
- template <class E>
- typename enable_if_c
- <
- is_error_condition_enum<E>::value,
- error_condition&
- >::type
- operator=(E _e)
- {*this = make_error_condition(_e); return *this;}
-
- void clear() {
- _val_ = 0;
- _cat_ = &generic_category();
- }
-
- int value() const {return _val_;}
-
- const error_category& category() const {return *_cat_;}
- std::string message() const;
-
- // explicit
- operator bool() const {return _val_ != 0;}
-};
-
-inline error_condition make_error_condition(errc _e) {
- return error_condition(static_cast<int>(_e), generic_category());
-}
-
-inline bool operator<(const error_condition& _x, const error_condition& _y) {
- return _x.category() < _y.category()
- || _x.category() == _y.category() && _x.value() < _y.value();
-}
-
-// error_code
-
-class error_code {
- int _val_;
- const error_category* _cat_;
-public:
- error_code() : _val_(0), _cat_(&system_category()) {}
-
- error_code(int _val, const error_category& _cat)
- : _val_(_val), _cat_(&_cat) {}
-
- template <class E>
- error_code(E _e, typename enable_if_c<
- is_error_code_enum<E>::value
- >::type* = 0) {
- *this = make_error_code(_e);
- }
-
- void assign(int _val, const error_category& _cat) {
- _val_ = _val;
- _cat_ = &_cat;
- }
-
- template <class E>
- typename enable_if_c
- <
- is_error_code_enum<E>::value,
- error_code&
- >::type
- operator=(E _e)
- {*this = make_error_code(_e); return *this;}
-
- void clear() {
- _val_ = 0;
- _cat_ = &system_category();
- }
-
- int value() const {return _val_;}
-
- const error_category& category() const {return *_cat_;}
-
- error_condition default_error_condition() const
- {return _cat_->default_error_condition(_val_);}
-
- std::string message() const;
-
- // explicit
- operator bool() const {return _val_ != 0;}
-};
-
-inline error_code make_error_code(errc _e) {
- return error_code(static_cast<int>(_e), generic_category());
-}
-
-inline bool operator<(const error_code& _x, const error_code& _y) {
- return _x.category() < _y.category()
- || _x.category() == _y.category() && _x.value() < _y.value();
-}
-
-inline bool operator==(const error_code& _x, const error_code& _y) {
- return _x.category() == _y.category() && _x.value() == _y.value();
-}
-
-inline bool operator==(const error_code& _x, const error_condition& _y) {
- return _x.category().equivalent(_x.value(), _y)
- || _y.category().equivalent(_x, _y.value());
-}
-
-inline bool operator==(const error_condition& _x, const error_code& _y) {
- return _y == _x;
-}
-
-inline bool operator==(const error_condition& _x, const error_condition& _y) {
- return _x.category() == _y.category() && _x.value() == _y.value();
-}
-
-inline bool operator!=(const error_code& _x, const error_code& _y) {
- return !(_x == _y);
-}
-
-inline bool operator!=(const error_code& _x, const error_condition& _y) {
- return !(_x == _y);
-}
-
-inline bool operator!=(const error_condition& _x, const error_code& _y) {
- return !(_x == _y);
-}
-
-inline bool operator!=(const error_condition& _x, const error_condition& _y) {
- return !(_x == _y);
-}
-
-// system_error
-
-class system_error : public std::runtime_error {
- error_code _ec_;
-public:
- system_error(error_code _ec, const std::string& _what_arg);
- system_error(error_code _ec, const char* _what_arg);
- system_error(error_code _ec);
- system_error(int _ev, const error_category& _ecat,
- const std::string& _what_arg);
- system_error(int _ev, const error_category& _ecat, const char* _what_arg);
- system_error(int _ev, const error_category& _ecat);
- ~system_error() throw();
-
- const error_code& code() const throw() {return _ec_;}
-
-private:
- static std::string _init(const error_code&, std::string);
-};
-
-void _throw_system_error(int ev, const char* what_arg);
-
-} // end namespace llvm
-
-#ifdef LLVM_ON_WIN32
-#include <Windows.h>
-#include <WinError.h>
-
-namespace llvm {
-
-// To construct an error_code after a API error:
-//
-// error_code( ::GetLastError(), system_category() )
-struct windows_error {
-enum _ {
- success = 0,
- // These names and values are based on Windows winerror.h
- invalid_function = ERROR_INVALID_FUNCTION,
- file_not_found = ERROR_FILE_NOT_FOUND,
- path_not_found = ERROR_PATH_NOT_FOUND,
- too_many_open_files = ERROR_TOO_MANY_OPEN_FILES,
- access_denied = ERROR_ACCESS_DENIED,
- invalid_handle = ERROR_INVALID_HANDLE,
- arena_trashed = ERROR_ARENA_TRASHED,
- not_enough_memory = ERROR_NOT_ENOUGH_MEMORY,
- invalid_block = ERROR_INVALID_BLOCK,
- bad_environment = ERROR_BAD_ENVIRONMENT,
- bad_format = ERROR_BAD_FORMAT,
- invalid_access = ERROR_INVALID_ACCESS,
- outofmemory = ERROR_OUTOFMEMORY,
- invalid_drive = ERROR_INVALID_DRIVE,
- current_directory = ERROR_CURRENT_DIRECTORY,
- not_same_device = ERROR_NOT_SAME_DEVICE,
- no_more_files = ERROR_NO_MORE_FILES,
- write_protect = ERROR_WRITE_PROTECT,
- bad_unit = ERROR_BAD_UNIT,
- not_ready = ERROR_NOT_READY,
- bad_command = ERROR_BAD_COMMAND,
- crc = ERROR_CRC,
- bad_length = ERROR_BAD_LENGTH,
- seek = ERROR_SEEK,
- not_dos_disk = ERROR_NOT_DOS_DISK,
- sector_not_found = ERROR_SECTOR_NOT_FOUND,
- out_of_paper = ERROR_OUT_OF_PAPER,
- write_fault = ERROR_WRITE_FAULT,
- read_fault = ERROR_READ_FAULT,
- gen_failure = ERROR_GEN_FAILURE,
- sharing_violation = ERROR_SHARING_VIOLATION,
- lock_violation = ERROR_LOCK_VIOLATION,
- wrong_disk = ERROR_WRONG_DISK,
- sharing_buffer_exceeded = ERROR_SHARING_BUFFER_EXCEEDED,
- handle_eof = ERROR_HANDLE_EOF,
- handle_disk_full= ERROR_HANDLE_DISK_FULL,
- rem_not_list = ERROR_REM_NOT_LIST,
- dup_name = ERROR_DUP_NAME,
- bad_net_path = ERROR_BAD_NETPATH,
- network_busy = ERROR_NETWORK_BUSY,
- // ...
- file_exists = ERROR_FILE_EXISTS,
- cannot_make = ERROR_CANNOT_MAKE,
- // ...
- broken_pipe = ERROR_BROKEN_PIPE,
- open_failed = ERROR_OPEN_FAILED,
- buffer_overflow = ERROR_BUFFER_OVERFLOW,
- disk_full= ERROR_DISK_FULL,
- // ...
- lock_failed = ERROR_LOCK_FAILED,
- busy = ERROR_BUSY,
- cancel_violation = ERROR_CANCEL_VIOLATION,
- already_exists = ERROR_ALREADY_EXISTS
- // ...
-
- // TODO: add more Windows errors
-};
- _ v_;
-
- windows_error(_ v) : v_(v) {}
- explicit windows_error(DWORD v) : v_(_(v)) {}
- operator int() const {return v_;}
-};
-
-
-template <> struct is_error_code_enum<windows_error> : true_type { };
-
-template <> struct is_error_code_enum<windows_error::_> : true_type { };
-
-inline error_code make_error_code(windows_error e) {
- return error_code(static_cast<int>(e), system_category());
-}
-
-} // end namespace llvm
-
-#endif // LLVM_ON_WINDOWS
-
-#endif
diff --git a/utils/TableGen/ARMDecoderEmitter.cpp b/utils/TableGen/ARMDecoderEmitter.cpp
index 533fca0..a2403e6 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];
@@ -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);
@@ -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.
//
@@ -1624,22 +1622,17 @@ 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;
// Ignore the non-Darwin BL instructions and the TPsoft (TLS) instruction.
- if (Name == "BL" || Name == "BL_pred" || Name == "BLX" || Name == "BX" ||
- Name == "TPsoft")
+ if (Name == "BL" || Name == "BL_pred" || Name == "BLX" ||
+ Name == "BLX_pred" || Name == "TPsoft")
return false;
// Ignore VDUPf[d|q] instructions known to conflict with VDUP32[d-q] for
@@ -1695,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.
@@ -1718,43 +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")
+ 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.
@@ -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 571a947..1faeb91 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 248ce4f..e3def41 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
@@ -68,6 +72,28 @@
// 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"
@@ -90,9 +116,8 @@ static cl::opt<std::string>
MatchPrefix("match-prefix", cl::init(""),
cl::desc("Only match instructions with the given prefix"));
-
namespace {
- class AsmMatcherInfo;
+class AsmMatcherInfo;
struct SubtargetFeatureInfo;
/// ClassInfo - Helper class for storing the information about a particular
@@ -142,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;
@@ -247,16 +276,19 @@ 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 operand name this is, if anything.
StringRef SrcOpName;
-
- explicit AsmOperand(StringRef T) : Token(T), Class(0) {}
+
+ /// The suboperand index within SrcOpName, or -1 for the entire operand.
+ int SubOpIdx;
+
+ explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1) {}
};
-
+
/// 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
@@ -267,90 +299,85 @@ struct MatchableInfo {
/// 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;
};
-
- /// OpInfo - This is the information about the instruction operand that is
- /// being populated.
- const CGIOperandList::OperandInfo *OpInfo;
-
- static ResOperand getRenderedOp(unsigned AsmOpNum,
- const CGIOperandList::OperandInfo *Op) {
+
+ /// 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.OpInfo = Op;
+ X.MINumOperands = NumOperands;
return X;
}
-
- static ResOperand getTiedOp(unsigned TiedOperandNum,
- const CGIOperandList::OperandInfo *Op) {
+
+ static ResOperand getTiedOp(unsigned TiedOperandNum) {
ResOperand X;
X.Kind = TiedOperand;
X.TiedOperandNum = TiedOperandNum;
- X.OpInfo = Op;
+ X.MINumOperands = 1;
return X;
}
-
- static ResOperand getImmOp(int64_t Val,
- const CGIOperandList::OperandInfo *Op) {
+
+ static ResOperand getImmOp(int64_t Val) {
ResOperand X;
X.Kind = ImmOperand;
X.ImmVal = Val;
- X.OpInfo = Op;
+ X.MINumOperands = 1;
return X;
}
-
- static ResOperand getRegOp(Record *Reg,
- const CGIOperandList::OperandInfo *Op) {
+
+ static ResOperand getRegOp(Record *Reg) {
ResOperand X;
X.Kind = RegOperand;
X.Register = Reg;
- X.OpInfo = Op;
+ 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;
@@ -362,7 +389,7 @@ struct MatchableInfo {
/// Mnemonic - This is the first token of the matched instruction, its
/// mnemonic.
StringRef Mnemonic;
-
+
/// 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
@@ -376,7 +403,7 @@ struct MatchableInfo {
/// ConvertToMCInst to convert parsed operands into an MCInst for this
/// function.
std::string ConversionFnKind;
-
+
MatchableInfo(const CodeGenInstruction &CGI)
: TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) {
}
@@ -384,26 +411,38 @@ struct MatchableInfo {
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;
+ 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();
@@ -417,7 +456,7 @@ struct MatchableInfo {
return AsmOperands.size() < RHS.AsmOperands.size();
// Compare lexicographically by operand. The matcher validates that other
- // orderings wouldn't be ambiguous using \see CouldMatchAmiguouslyWith().
+ // 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;
@@ -428,14 +467,14 @@ struct MatchableInfo {
return false;
}
- /// CouldMatchAmiguouslyWith - Check whether this matchable 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 MatchableInfo &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 (AsmOperands.size() != RHS.AsmOperands.size())
return false;
@@ -468,7 +507,7 @@ struct MatchableInfo {
}
void dump();
-
+
private:
void TokenizeAsmString(const AsmMatcherInfo &Info);
};
@@ -483,15 +522,34 @@ struct SubtargetFeatureInfo {
unsigned Index;
SubtargetFeatureInfo(Record *D, unsigned Idx) : TheDef(D), Index(Idx) {}
-
+
/// \brief The name of the enumerated constant identifying this feature.
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;
@@ -507,12 +565,15 @@ public:
/// 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;
/// Map of Predicate records to their subtarget information.
std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
-
+
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo*> TokenClasses;
@@ -528,7 +589,8 @@ private:
ClassInfo *getTokenClass(StringRef Token);
/// getOperandClass - Lookup or create the class for the given operand.
- ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI);
+ ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI,
+ int SubOpIdx = -1);
/// BuildRegisterClasses - Build the ClassInfo* instances for register
/// classes.
@@ -538,19 +600,23 @@ private:
/// operand classes.
void BuildOperandClasses();
- void BuildInstructionOperandReference(MatchableInfo *II,
- StringRef OpName,
- MatchableInfo::AsmOperand &Op);
- void BuildAliasOperandReference(MatchableInfo *II,
- StringRef OpName,
+ void BuildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
+ unsigned AsmOpIdx);
+ void BuildAliasOperandReference(MatchableInfo *II, StringRef OpName,
MatchableInfo::AsmOperand &Op);
-
+
public:
- AsmMatcherInfo(Record *AsmParser, CodeGenTarget &Target);
+ AsmMatcherInfo(Record *AsmParser,
+ CodeGenTarget &Target,
+ RecordKeeper &Records);
/// BuildInfo - Construct the various tables used during matching.
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 {
@@ -559,6 +625,10 @@ public:
SubtargetFeatures.find(Def);
return I == SubtargetFeatures.end() ? 0 : I->second;
}
+
+ RecordKeeper &getRecords() const {
+ return Records;
+ }
};
}
@@ -577,16 +647,16 @@ 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))
@@ -633,7 +703,7 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
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;
@@ -662,7 +732,7 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
}
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?");
@@ -670,25 +740,23 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
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());
}
-
-
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() &&
@@ -696,10 +764,10 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
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.
+ // 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.
@@ -710,7 +778,7 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
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) {
@@ -728,11 +796,10 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
return false;
}
}
-
+
return true;
}
-
/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
/// register, return the register name, otherwise return a null StringRef.
Record *MatchableInfo::
@@ -740,16 +807,16 @@ 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() +
@@ -757,7 +824,6 @@ getSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info) const{
throw TGError(TheDef->getLoc(), Err);
}
-
static std::string getEnumNameForToken(StringRef Str) {
std::string Res;
@@ -766,6 +832,8 @@ static std::string getEnumNameForToken(StringRef Str) {
case '*': Res += "_STAR_"; break;
case '%': Res += "_PCT_"; break;
case ':': Res += "_COLON_"; break;
+ case '!': Res += "_EXCLAIM_"; break;
+ case '.': Res += "_DOT_"; break;
default:
if (isalnum(*it))
Res += *it;
@@ -788,6 +856,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
Entry->ValueName = Token;
Entry->PredicateMethod = "<invalid>";
Entry->RenderMethod = "<invalid>";
+ Entry->ParserMethod = "";
Classes.push_back(Entry);
}
@@ -795,19 +864,24 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
}
ClassInfo *
-AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI) {
- if (OI.Rec->isSubClassOf("RegisterClass")) {
- if (ClassInfo *CI = RegisterClassClasses[OI.Rec])
+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(OI.Rec->getLoc(), "register class has no class info!");
+ throw TGError(Rec->getLoc(), "register class has no class info!");
}
- assert(OI.Rec->isSubClassOf("Operand") && "Unexpected operand!");
- Record *MatchClass = OI.Rec->getValueAsDef("ParserMatchClass");
+ assert(Rec->isSubClassOf("Operand") && "Unexpected operand!");
+ Record *MatchClass = Rec->getValueAsDef("ParserMatchClass");
if (ClassInfo *CI = AsmOperandClasses[MatchClass])
return CI;
- throw TGError(OI.Rec->getLoc(), "operand has no match class!");
+ throw TGError(Rec->getLoc(), "operand has no match class!");
}
void AsmMatcherInfo::
@@ -851,7 +925,7 @@ BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
ContainingSet = *it;
continue;
}
-
+
std::set<Record*> Tmp;
std::swap(Tmp, ContainingSet);
std::insert_iterator< std::set<Record*> > II(ContainingSet,
@@ -983,16 +1057,56 @@ void AsmMatcherInfo::BuildOperandClasses() {
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, CodeGenTarget &target)
- : AsmParser(asmParser), Target(target),
+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() {
// Build information about all of the AssemblerPredicates.
@@ -1003,17 +1117,17 @@ void AsmMatcherInfo::BuildInfo() {
// 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.
SmallPtrSet<Record*, 16> SingletonRegisters;
@@ -1029,15 +1143,15 @@ void AsmMatcherInfo::BuildInfo() {
// Ignore "codegen only" instructions.
if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
continue;
-
+
// 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 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.
@@ -1050,26 +1164,26 @@ void AsmMatcherInfo::BuildInfo() {
}
}
}
-
+
OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
II->Initialize(*this, SingletonRegisters);
-
+
// Ignore instructions which shouldn't be matched and diagnose invalid
// instruction definitions with an error.
if (!II->Validate(CommentDelimiter, true))
continue;
-
+
// 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 =
@@ -1077,13 +1191,20 @@ void AsmMatcherInfo::BuildInfo() {
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());
}
@@ -1100,7 +1221,9 @@ void AsmMatcherInfo::BuildInfo() {
MatchableInfo *II = *it;
// Parse the tokens after the mnemonic.
- for (unsigned i = 0, e = II->AsmOperands.size(); i != e; ++i) {
+ // 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;
@@ -1122,20 +1245,20 @@ void AsmMatcherInfo::BuildInfo() {
Op.Class = getTokenClass(Token);
continue;
}
-
+
// Otherwise this is an operand reference.
StringRef OperandName;
if (Token[1] == '{')
OperandName = Token.substr(2, Token.size() - 3);
else
OperandName = Token.substr(1);
-
+
if (II->DefRec.is<const CodeGenInstruction*>())
- BuildInstructionOperandReference(II, OperandName, Op);
+ BuildInstructionOperandReference(II, OperandName, i);
else
BuildAliasOperandReference(II, OperandName, Op);
}
-
+
if (II->DefRec.is<const CodeGenInstruction*>())
II->BuildInstructionResultOperands();
else
@@ -1151,18 +1274,40 @@ void AsmMatcherInfo::BuildInfo() {
void AsmMatcherInfo::
BuildInstructionOperandReference(MatchableInfo *II,
StringRef OperandName,
- MatchableInfo::AsmOperand &Op) {
+ 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;
+ }
+ }
+
// Set up the operand class.
- Op.Class = getOperandClass(Operands[Idx]);
+ Op->Class = getOperandClass(Operands[Idx], Op->SubOpIdx);
// If the named operand is tied, canonicalize it to the untied operand.
// For example, something like:
@@ -1176,15 +1321,12 @@ BuildInstructionOperandReference(MatchableInfo *II,
if (OITied != -1) {
// The tied operand index is an MIOperand index, find the operand that
// contains it.
- for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- if (Operands[i].MIOperandNo == unsigned(OITied)) {
- OperandName = Operands[i].Name;
- break;
- }
- }
+ std::pair<unsigned, unsigned> Idx = Operands.getSubOperandNumber(OITied);
+ OperandName = Operands[Idx.first].Name;
+ Op->SubOpIdx = Idx.second;
}
-
- Op.SrcOpName = OperandName;
+
+ Op->SrcOpName = OperandName;
}
/// BuildAliasOperandReference - When parsing an operand reference out of the
@@ -1194,15 +1336,17 @@ 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.getResultInstOperandIndexForResultOperandIndex(i);
- Op.Class = getOperandClass(CGA.ResultInst->Operands[ResultIdx]);
+ 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;
}
@@ -1213,7 +1357,7 @@ void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
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) {
@@ -1222,73 +1366,90 @@ void MatchableInfo::BuildInstructionResultOperands() {
// 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, &OpInfo));
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
continue;
}
-
- // Find out what operand from the asmparser that this MCInst operand comes
- // from.
+
+ // 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!");
- if (!OpInfo.Name.empty() && SrcOperand != -1) {
- ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
+ // 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;
}
-
- throw TGError(TheDef->getLoc(), "Instruction '" +
- TheDef->getName() + "' has operand '" + OpInfo.Name +
- "' that doesn't appear in asm string!");
+
+ // 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));
+ }
}
}
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];
-
+ const CGIOperandList::OperandInfo *OpInfo = &ResultInst->Operands[i];
+
// If this is a tied operand, just copy from the previously handled operand.
- int TiedOp = OpInfo.getTiedRegister();
+ int TiedOp = OpInfo->getTiedRegister();
if (TiedOp != -1) {
- ResOperands.push_back(ResOperand::getTiedOp(TiedOp, &OpInfo));
- continue;
- }
-
- // Find out what operand from the asmparser that this MCInst operand comes
- // from.
- switch (CGA.ResultOperands[AliasOpNo].Kind) {
- case CodeGenInstAlias::ResultOperand::K_Record: {
- StringRef Name = CGA.ResultOperands[AliasOpNo++].getName();
- int SrcOperand = FindAsmOperandNamed(Name);
- if (SrcOperand != -1) {
- ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
- continue;
- }
-
- throw TGError(TheDef->getLoc(), "Instruction '" +
- TheDef->getName() + "' has operand '" + OpInfo.Name +
- "' that doesn't appear in asm string!");
- }
- case CodeGenInstAlias::ResultOperand::K_Imm: {
- int64_t ImmVal = CGA.ResultOperands[AliasOpNo++].getImm();
- ResOperands.push_back(ResOperand::getImmOp(ImmVal, &OpInfo));
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
continue;
}
- case CodeGenInstAlias::ResultOperand::K_Reg: {
- Record *Reg = CGA.ResultOperands[AliasOpNo++].getRegister();
- ResOperands.push_back(ResOperand::getRegOp(Reg, &OpInfo));
- 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,
+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
@@ -1300,7 +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";
@@ -1320,11 +1482,31 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
ie = Infos.end(); it != ie; ++it) {
MatchableInfo &II = **it;
+ // 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;
+
+ // Check if we have already generated this signature.
+ if (!GeneratedFns.insert(Signature).second)
+ continue;
+
+ // 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";
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];
@@ -1334,7 +1516,7 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
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 += "__";
@@ -1342,19 +1524,19 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
Signature += "Reg";
else
Signature += Op.Class->ClassName;
- Signature += utostr(OpInfo.OpInfo->MINumOperands);
+ Signature += utostr(OpInfo.MINumOperands);
Signature += "_" + itostr(OpInfo.AsmOperandNum);
-
+
CaseOS << " ((" << TargetOperandClass << "*)Operands["
<< (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod
- << "(Inst, " << OpInfo.OpInfo->MINumOperands << ");\n";
+ << "(Inst, " << OpInfo.MINumOperands << ");\n";
break;
}
-
+
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.OpInfo->MINumOperands == 1 && "Not a singular MCOperand");
+ //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";
@@ -1368,13 +1550,18 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
break;
}
case MatchableInfo::ResOperand::RegOperand: {
- std::string N = getQualifiedName(OpInfo.Register);
- CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n";
- Signature += "__reg" + OpInfo.Register->getName();
- }
+ 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;
// Check if we have already generated this signature.
@@ -1386,12 +1573,13 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
CvtOS << " case " << Signature << ":\n";
CvtOS << CaseOS.str();
- CvtOS << " return;\n";
+ 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.
@@ -1433,32 +1621,35 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitClassifyOperand - Emit the function to classify an operand.
-static void EmitClassifyOperand(AsmMatcherInfo &Info,
- raw_ostream &OS) {
- OS << "static MatchClassKind ClassifyOperand(MCParsedAsmOperand *GOp) {\n"
- << " " << Info.Target.getName() << "Operand &Operand = *("
+/// 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";
+ 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 " << Info.Target.getName() << "::"
- << it->first->getName() << ": return " << it->second->Name << ";\n";
+ << it->first->getName() << ": OpKind = " << it->second->Name
+ << "; break;\n";
OS << " }\n";
+ OS << " return IsSubclass(OpKind, Kind);\n";
OS << " }\n\n";
- // Classify user defined operands.
+ // 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;
@@ -1466,30 +1657,14 @@ static void EmitClassifyOperand(AsmMatcherInfo &Info,
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";
}
@@ -1540,8 +1715,6 @@ static void EmitIsSubclass(CodeGenTarget &Target,
OS << "}\n\n";
}
-
-
/// EmitMatchTokenString - Emit the function to match a token string to the
/// appropriate match class value.
static void EmitMatchTokenString(CodeGenTarget &Target,
@@ -1637,18 +1810,18 @@ static std::string GetAliasRequiredFeatures(Record *R,
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;
@@ -1657,17 +1830,21 @@ static std::string GetAliasRequiredFeatures(Record *R,
/// 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 =
- Records.getAllDerivedDefinitions("MnemonicAlias");
+ 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);
@@ -1686,11 +1863,11 @@ static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
// 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()) {
@@ -1700,43 +1877,190 @@ static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
"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";
-
+ 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, Target);
+ AsmMatcherInfo Info(AsmParser, Target, Records);
Info.BuildInfo();
// Sort the instruction table using the partial order on classes. We use
@@ -1760,7 +2084,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
MatchableInfo &A = *Info.Matchables[i];
MatchableInfo &B = *Info.Matchables[j];
- if (A.CouldMatchAmiguouslyWith(B)) {
+ if (A.CouldMatchAmbiguouslyWith(B)) {
errs() << "warning: ambiguous matchables:\n";
A.dump();
errs() << "\nis incomparable with:\n";
@@ -1775,6 +2099,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< " ambiguous matchables!\n";
});
+ // Compute the information on the custom operand parsing.
+ Info.BuildOperandMatchInfo();
+
// Write the output.
EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
@@ -1782,21 +2109,42 @@ void AsmMatcherEmitter::run(raw_ostream &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 << " // 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_Success, Match_MnemonicFail, Match_InvalidOperand,\n";
- OS << " Match_MissingFeature\n";
+ OS << " Match_ConversionFail,\n";
+ OS << " Match_InvalidOperand,\n";
+ OS << " Match_MissingFeature,\n";
+ OS << " Match_MnemonicFail,\n";
+ OS << " Match_Success\n";
OS << " };\n";
- OS << " MatchResultTy MatchInstructionImpl(const "
- << "SmallVectorImpl<MCParsedAsmOperand*>"
- << " &Operands, MCInst &Inst, unsigned &ErrorInfo);\n\n";
- OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\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";
@@ -1815,9 +2163,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// 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.Matchables, OS);
+ EmitConvertToMCInst(Target, ClassName, Info.Matchables, OS);
// Emit the enumeration for classes which participate in matching.
EmitMatchClassEnumeration(Target, Info.Classes, OS);
@@ -1825,12 +2173,12 @@ 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(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(Info, OS);
@@ -1841,7 +2189,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
it != ie; ++it)
MaxNumOperands = std::max(MaxNumOperands, (*it)->AsmOperands.size());
-
// Emit the static match table; unused classes get initalized to 0 which is
// guaranteed to be InvalidMatchClass.
//
@@ -1861,7 +2208,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " unsigned RequiredFeatures;\n";
OS << " };\n\n";
- OS << "// Predicate for searching for an opcode.\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";
@@ -1884,7 +2231,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
it != ie; ++it) {
MatchableInfo &II = **it;
-
OS << " { " << Target.getName() << "::"
<< II.getResultInst()->TheDef->getName() << ", \"" << II.Mnemonic << "\""
<< ", " << II.ConversionFnKind << ", { ";
@@ -1910,6 +2256,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
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"
@@ -1929,7 +2285,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
OS << " ApplyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
}
-
+
// Emit code to compute the class list for this operand vector.
OS << " // Eliminate obvious mismatches.\n";
OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n";
@@ -1937,26 +2293,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " return Match_InvalidOperand;\n";
OS << " }\n\n";
- OS << " // Compute the class list for this operand vector.\n";
- OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n";
- OS << " for (unsigned i = 1, e = Operands.size(); i != e; ++i) {\n";
- OS << " Classes[i-1] = ClassifyOperand(Operands[i]);\n\n";
-
- OS << " // Check for invalid operands before matching.\n";
- OS << " if (Classes[i-1] == InvalidMatchClass) {\n";
- OS << " ErrorInfo = i;\n";
- OS << " return Match_InvalidOperand;\n";
- OS << " }\n";
- OS << " }\n\n";
-
- OS << " // Mark unused classes.\n";
- OS << " for (unsigned i = Operands.size()-1, 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 << " // Set ErrorInfo to the operand that mismatches if it is\n";
OS << " // wrong for all instances of the instruction.\n";
OS << " ErrorInfo = ~0U;\n";
@@ -1980,14 +2319,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit check that the subclasses match.
OS << " bool OperandsValid = true;\n";
OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n";
- OS << " if (IsSubclass(Classes[i], it->Classes[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 << " if (it == MnemonicRange.first || ErrorInfo <= i+1)\n";
OS << " ErrorInfo = i+1;\n";
- OS << " else\n";
- OS << " ErrorInfo = ~0U;";
OS << " // Otherwise, just reject this instance of the mnemonic.\n";
OS << " OperandsValid = false;\n";
OS << " break;\n";
@@ -2001,9 +2342,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " HadMatchOtherThanFeatures = true;\n";
OS << " continue;\n";
OS << " }\n";
-
OS << "\n";
- OS << " ConvertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\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";
// Call the post-processing function, if used.
std::string InsnCleanupFn =
@@ -2019,5 +2364,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " return Match_InvalidOperand;\n";
OS << "}\n\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 1bca660..cd31e0c 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -240,7 +240,7 @@ 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");
@@ -459,7 +459,7 @@ 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();
@@ -501,7 +501,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
}
void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
- CodeGenTarget Target;
+ CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
@@ -542,7 +542,255 @@ void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
<< "}\n\n#endif\n";
}
+void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
+ CodeGenTarget Target(Records);
+ Record *AsmWriter = Target.getAsmWriter();
+
+ O << "\n#ifdef PRINT_ALIAS_INSTR\n";
+ O << "#undef PRINT_ALIAS_INSTR\n\n";
+
+ // Enumerate the register classes.
+ const std::vector<CodeGenRegisterClass> &RegisterClasses =
+ Target.getRegisterClasses();
+
+ O << "namespace { // Register classes\n";
+ O << " enum RegClass {\n";
+
+ // Emit the register enum value for each RegisterClass.
+ for (unsigned I = 0, E = RegisterClasses.size(); I != E; ++I) {
+ if (I != 0) O << ",\n";
+ O << " RC_" << RegisterClasses[I].TheDef->getName();
+ }
+
+ O << "\n };\n";
+ O << "} // end anonymous namespace\n\n";
+
+ // Emit a function that returns 'true' if a regsiter is part of a particular
+ // register class. I.e., RAX is part of GR64 on X86.
+ O << "static bool regIsInRegisterClass"
+ << "(unsigned RegClass, unsigned Reg) {\n";
+
+ // Emit the switch that checks if a register belongs to a particular register
+ // class.
+ O << " switch (RegClass) {\n";
+ O << " default: break;\n";
+
+ for (unsigned I = 0, E = RegisterClasses.size(); I != E; ++I) {
+ const CodeGenRegisterClass &RC = RegisterClasses[I];
+
+ // Give the register class a legal C name if it's anonymous.
+ std::string Name = RC.TheDef->getName();
+ O << " case RC_" << Name << ":\n";
+
+ // Emit the register list now.
+ unsigned IE = RC.Elements.size();
+ if (IE == 1) {
+ O << " if (Reg == " << getQualifiedName(RC.Elements[0]) << ")\n";
+ O << " return true;\n";
+ } else {
+ O << " switch (Reg) {\n";
+ O << " default: break;\n";
+
+ for (unsigned II = 0; II != IE; ++II) {
+ Record *Reg = RC.Elements[II];
+ O << " case " << getQualifiedName(Reg) << ":\n";
+ }
+
+ O << " return true;\n";
+ O << " }\n";
+ }
+
+ O << " break;\n";
+ }
+
+ O << " }\n\n";
+ O << " return false;\n";
+ O << "}\n\n";
+
+ // Emit the method that prints the alias instruction.
+ std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
+
+ bool isMC = AsmWriter->getValueAsBit("isMCAsmWriter");
+ const char *MachineInstrClassName = isMC ? "MCInst" : "MachineInstr";
+
+ O << "bool " << Target.getName() << ClassName
+ << "::printAliasInstr(const " << MachineInstrClassName
+ << " *MI, raw_ostream &OS) {\n";
+
+ std::vector<Record*> AllInstAliases =
+ Records.getAllDerivedDefinitions("InstAlias");
+
+ // Create a map from the qualified name to a list of potential matches.
+ std::map<std::string, std::vector<CodeGenInstAlias*> > AliasMap;
+ for (std::vector<Record*>::iterator
+ I = AllInstAliases.begin(), E = AllInstAliases.end(); I != E; ++I) {
+ CodeGenInstAlias *Alias = new CodeGenInstAlias(*I, Target);
+ const Record *R = *I;
+ const DagInit *DI = R->getValueAsDag("ResultInst");
+ const DefInit *Op = dynamic_cast<const DefInit*>(DI->getOperator());
+ AliasMap[getQualifiedName(Op->getDef())].push_back(Alias);
+ }
+
+ if (AliasMap.empty() || !isMC) {
+ // FIXME: Support MachineInstr InstAliases?
+ O << " return true;\n";
+ O << "}\n\n";
+ O << "#endif // PRINT_ALIAS_INSTR\n";
+ return;
+ }
+
+ O << " StringRef AsmString;\n";
+ O << " std::map<StringRef, unsigned> OpMap;\n";
+ O << " switch (MI->getOpcode()) {\n";
+ O << " default: return true;\n";
+
+ for (std::map<std::string, std::vector<CodeGenInstAlias*> >::iterator
+ I = AliasMap.begin(), E = AliasMap.end(); I != E; ++I) {
+ std::vector<CodeGenInstAlias*> &Aliases = I->second;
+
+ std::map<std::string, unsigned> CondCount;
+ std::map<std::string, std::string> BodyMap;
+
+ std::string AsmString = "";
+
+ for (std::vector<CodeGenInstAlias*>::iterator
+ II = Aliases.begin(), IE = Aliases.end(); II != IE; ++II) {
+ const CodeGenInstAlias *CGA = *II;
+ AsmString = CGA->AsmString;
+ unsigned Indent = 8;
+ unsigned LastOpNo = CGA->ResultInstOperandIndex.size();
+
+ std::string Cond;
+ raw_string_ostream CondO(Cond);
+
+ CondO << "if (MI->getNumOperands() == " << LastOpNo;
+
+ std::map<StringRef, unsigned> OpMap;
+ bool CantHandle = false;
+
+ for (unsigned i = 0, e = LastOpNo; i != e; ++i) {
+ const CodeGenInstAlias::ResultOperand &RO = CGA->ResultOperands[i];
+
+ switch (RO.Kind) {
+ default: assert(0 && "unexpected InstAlias operand kind");
+ case CodeGenInstAlias::ResultOperand::K_Record: {
+ const Record *Rec = RO.getRecord();
+ StringRef ROName = RO.getName();
+
+ if (Rec->isSubClassOf("RegisterClass")) {
+ CondO << " &&\n";
+ CondO.indent(Indent) << "MI->getOperand(" << i << ").isReg() &&\n";
+ if (OpMap.find(ROName) == OpMap.end()) {
+ OpMap[ROName] = i;
+ CondO.indent(Indent)
+ << "regIsInRegisterClass(RC_"
+ << CGA->ResultOperands[i].getRecord()->getName()
+ << ", MI->getOperand(" << i << ").getReg())";
+ } else {
+ CondO.indent(Indent)
+ << "MI->getOperand(" << i
+ << ").getReg() == MI->getOperand("
+ << OpMap[ROName] << ").getReg()";
+ }
+ } else {
+ assert(Rec->isSubClassOf("Operand") && "Unexpected operand!");
+ // FIXME: We need to handle these situations.
+ CantHandle = true;
+ break;
+ }
+
+ break;
+ }
+ case CodeGenInstAlias::ResultOperand::K_Imm:
+ CondO << " &&\n";
+ CondO.indent(Indent) << "MI->getOperand(" << i << ").getImm() == ";
+ CondO << CGA->ResultOperands[i].getImm();
+ break;
+ case CodeGenInstAlias::ResultOperand::K_Reg:
+ CondO << " &&\n";
+ CondO.indent(Indent) << "MI->getOperand(" << i << ").getReg() == ";
+ CondO << Target.getName() << "::"
+ << CGA->ResultOperands[i].getRegister()->getName();
+ break;
+ }
+
+ if (CantHandle) break;
+ }
+
+ if (CantHandle) continue;
+
+ CondO << ")";
+ std::string Body;
+ raw_string_ostream BodyO(Body);
+
+ BodyO << " // " << CGA->Result->getAsString() << "\n";
+ BodyO << " AsmString = \"" << AsmString << "\";\n";
+
+ for (std::map<StringRef, unsigned>::iterator
+ III = OpMap.begin(), IIE = OpMap.end(); III != IIE; ++III)
+ BodyO << " OpMap[\"" << III->first << "\"] = "
+ << III->second << ";\n";
+
+ ++CondCount[CondO.str()];
+ BodyMap[CondO.str()] = BodyO.str();
+ }
+
+ std::string Code;
+ raw_string_ostream CodeO(Code);
+
+ bool EmitElse = false;
+ for (std::map<std::string, unsigned>::iterator
+ II = CondCount.begin(), IE = CondCount.end(); II != IE; ++II) {
+ if (II->second != 1) continue;
+ CodeO << " ";
+ if (EmitElse) CodeO << "} else ";
+ CodeO << II->first << " {\n";
+ CodeO << BodyMap[II->first];
+ EmitElse = true;
+ }
+
+ if (CodeO.str().empty()) continue;
+
+ O << " case " << I->first << ":\n";
+ O << CodeO.str();
+ O << " }\n";
+ O << " break;\n";
+ }
+
+ O << " }\n\n";
+
+ // Code that prints the alias, replacing the operands with the ones from the
+ // MCInst.
+ O << " if (AsmString.empty()) return true;\n";
+ O << " std::pair<StringRef, StringRef> ASM = AsmString.split(' ');\n";
+ O << " OS << '\\t' << ASM.first;\n";
+
+ O << " if (!ASM.second.empty()) {\n";
+ O << " OS << '\\t';\n";
+ O << " for (StringRef::iterator\n";
+ O << " I = ASM.second.begin(), E = ASM.second.end(); I != E; ) {\n";
+ O << " if (*I == '$') {\n";
+ O << " StringRef::iterator Start = ++I;\n";
+ O << " while (I != E &&\n";
+ O << " ((*I >= 'a' && *I <= 'z') ||\n";
+ O << " (*I >= 'A' && *I <= 'Z') ||\n";
+ O << " (*I >= '0' && *I <= '9') ||\n";
+ O << " *I == '_'))\n";
+ O << " ++I;\n";
+ O << " StringRef Name(Start, I - Start);\n";
+ O << " printOperand(MI, OpMap[Name], OS);\n";
+ O << " } else {\n";
+ O << " OS << *I++;\n";
+ O << " }\n";
+ O << " }\n";
+ O << " }\n\n";
+
+ O << " return false;\n";
+ O << "}\n\n";
+
+ O << "#endif // PRINT_ALIAS_INSTR\n";
+}
void AsmWriterEmitter::run(raw_ostream &O) {
EmitSourceFileHeader("Assembly Writer Source Fragment", O);
@@ -550,5 +798,6 @@ void AsmWriterEmitter::run(raw_ostream &O) {
EmitPrintInstruction(O);
EmitGetRegisterName(O);
EmitGetInstructionName(O);
+ EmitPrintAliasInstruction(O);
}
diff --git a/utils/TableGen/AsmWriterEmitter.h b/utils/TableGen/AsmWriterEmitter.h
index 9f7d776..5e8d6f5 100644
--- a/utils/TableGen/AsmWriterEmitter.h
+++ b/utils/TableGen/AsmWriterEmitter.h
@@ -38,6 +38,7 @@ private:
void EmitPrintInstruction(raw_ostream &o);
void EmitGetRegisterName(raw_ostream &o);
void EmitGetInstructionName(raw_ostream &o);
+ void EmitPrintAliasInstruction(raw_ostream &O);
AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
assert(ID < NumberedInstructions.size());
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 5bafcec..514b191 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,7 +1,9 @@
set(LLVM_REQUIRES_EH 1)
set(LLVM_REQUIRES_RTTI 1)
-add_executable(tblgen
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_TOOLS_BINARY_DIR})
+
+add_llvm_utility(tblgen
ARMDecoderEmitter.cpp
AsmMatcherEmitter.cpp
AsmWriterEmitter.cpp
@@ -10,6 +12,7 @@ add_executable(tblgen
ClangASTNodesEmitter.cpp
ClangAttrEmitter.cpp
ClangDiagnosticsEmitter.cpp
+ ClangSACheckersEmitter.cpp
CodeEmitterGen.cpp
CodeGenDAGPatterns.cpp
CodeGenInstruction.cpp
@@ -22,6 +25,7 @@ add_executable(tblgen
DisassemblerEmitter.cpp
EDEmitter.cpp
FastISelEmitter.cpp
+ FixedLenDecoderEmitter.cpp
InstrEnumEmitter.cpp
InstrInfoEmitter.cpp
IntrinsicEmitter.cpp
@@ -41,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/ClangASTNodesEmitter.h b/utils/TableGen/ClangASTNodesEmitter.h
index abf9c9a..712333b 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 db10d79..f8bc07e 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -45,6 +45,7 @@ std::string ReadPCHRecord(StringRef type) {
.EndsWith("Decl *", "cast_or_null<" + std::string(type, 0, type.size()-1) +
">(GetDecl(Record[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");
}
@@ -462,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;
@@ -494,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 << " , ";
@@ -558,31 +561,72 @@ 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";
+
+ OS << "#ifndef INHERITABLE_PARAM_ATTR\n";
+ OS << "#define INHERITABLE_PARAM_ATTR(NAME) ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_INHERITABLE_PARAM_ATTR\n";
+ OS << "#define LAST_INHERITABLE_PARAM_ATTR(NAME)"
+ " INHERITABLE_PARAM_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ Record *InhClass = Records.getClass("InheritableAttr");
+ Record *InhParamClass = Records.getClass("InheritableParamAttr");
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
+ NonInhAttrs, InhAttrs, InhParamAttrs;
+ for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
+ i != e; ++i) {
+ if ((*i)->isSubClassOf(InhParamClass))
+ InhParamAttrs.push_back(*i);
+ else if ((*i)->isSubClassOf(InhClass))
+ InhAttrs.push_back(*i);
+ else
+ NonInhAttrs.push_back(*i);
}
+ EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
+ 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 LAST_INHERITABLE_PARAM_ATTR\n";
OS << "#undef ATTR\n";
}
void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
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;
@@ -596,6 +640,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) {
@@ -609,6 +655,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";
}
@@ -616,6 +664,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;
@@ -627,9 +676,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";
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 75b6252..60e67c4 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 0000000..8865db3
--- /dev/null
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -0,0 +1,230 @@
+//=- 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];
+ info.Hidden = R->getValueAsBit("Hidden");
+ 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 0000000..6bd1635
--- /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 9dbb8ee..957dd19 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -19,6 +19,7 @@
#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
@@ -141,7 +142,7 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
continue;
}
- // Figure out the consequtive range of bits covered by this operand, in
+ // Figure out the consecutive range of bits covered by this operand, in
// order to generate better encoding code.
int beginInstBit = bit;
int beginVarBit = varBit;
@@ -198,14 +199,13 @@ std::string CodeEmitterGen::getInstructionCase(Record *R,
}
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();
@@ -253,7 +253,8 @@ void CodeEmitterGen::run(raw_ostream &o) {
Record *R = *IC;
if (R->getValueAsString("Namespace") == "TargetOpcode")
continue;
- const std::string &InstName = R->getName();
+ const std::string &InstName = R->getValueAsString("Namespace") + "::"
+ + R->getName();
std::string Case = getInstructionCase(R, Target);
CaseMap[Case].push_back(InstName);
@@ -263,7 +264,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
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
@@ -274,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 2b87795..a874d97 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>
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index 6c89453..aa60f87 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.
@@ -505,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)
@@ -514,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);
@@ -527,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);
@@ -535,7 +668,7 @@ static unsigned getPatternSize(const TreePatternNode *P,
++Size;
}
}
-
+
return Size;
}
@@ -576,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")) {
@@ -596,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);
@@ -621,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';
@@ -644,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:
@@ -679,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,
@@ -702,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;
}
@@ -721,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");
@@ -732,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") {
@@ -754,8 +902,8 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
exit(1);
}
}
-
-
+
+
// Parse the type constraints.
std::vector<Record*> ConstraintList =
TypeProfile->getValueAsListOfDefs("Constraints");
@@ -770,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:
@@ -802,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;
@@ -824,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.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);
@@ -865,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)
@@ -903,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)
@@ -947,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()) {
@@ -975,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) {
@@ -994,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 " +
@@ -1012,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);
@@ -1026,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);
@@ -1041,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));
@@ -1065,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);
@@ -1083,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);
}
@@ -1103,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);
}
@@ -1114,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());
@@ -1129,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);
}
@@ -1149,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.
@@ -1176,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;
@@ -1205,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");
@@ -1241,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.
@@ -1260,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);
@@ -1278,37 +1426,37 @@ 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
@@ -1317,7 +1465,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
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") {
@@ -1325,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") {
@@ -1356,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.
@@ -1364,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")) {
@@ -1395,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() +
@@ -1408,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.
@@ -1438,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;
@@ -1452,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());
@@ -1469,7 +1617,7 @@ bool TreePatternNode::canPatternMatch(std::string &Reason,
}
}
}
-
+
return true;
}
@@ -1509,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));
}
@@ -1518,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))
@@ -1526,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()) {
@@ -1538,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());
@@ -1561,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") ||
@@ -1597,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" &&
@@ -1612,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);
@@ -1635,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());
@@ -1701,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) {
@@ -1727,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");
@@ -1735,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) {
@@ -1743,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();
@@ -1766,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) {
@@ -1785,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();
@@ -1795,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();
@@ -1866,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());
@@ -1890,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)) ||
@@ -1906,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() + "'!");
@@ -1916,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 {
@@ -1940,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());
}
@@ -1954,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;
@@ -1966,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 '" +
@@ -2036,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");
@@ -2059,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!");
@@ -2073,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.
@@ -2083,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!");
@@ -2124,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);
@@ -2257,7 +2407,7 @@ static void InferFromPattern(const CodeGenInstruction &Inst,
"which already inferred this.\n", Inst.TheDef->getName().c_str());
HasSideEffects = true;
}
-
+
if (Inst.Operands.isVariadic)
IsVariadic = true; // Can warn if we want.
}
@@ -2267,20 +2417,20 @@ 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.Operands.size() != 0) {
@@ -2291,40 +2441,40 @@ void CodeGenDAGPatterns::ParseInstructions() {
} else {
// Assume the first operand is the result.
Results.push_back(InstInfo.Operands[0].Rec);
-
+
// The rest are inputs.
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) {
@@ -2355,25 +2505,25 @@ void CodeGenDAGPatterns::ParseInstructions() {
I->error("'" + InstResults.begin()->first +
"' set but does not appear in operand list!");
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.Operands[i].Rec != R)
I->error("Operand $" + OpName + " class mismatch!");
-
+
// Remember the return type.
Results.push_back(CGI.Operands[i].Rec);
-
+
// Okay, this one checks out.
InstResults.erase(OpName);
}
@@ -2406,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();
@@ -2415,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);
@@ -2429,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!");
@@ -2457,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(),
@@ -2479,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(),
@@ -2494,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()) {
@@ -2506,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);
@@ -2519,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 =
@@ -2527,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;
@@ -2543,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);
}
@@ -2579,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))
@@ -2593,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;
}
@@ -2612,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 {
@@ -2633,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
@@ -2653,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
@@ -2668,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)
@@ -2677,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;
@@ -2705,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"),
@@ -2724,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,
@@ -2733,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());
@@ -2754,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)
@@ -2778,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].
@@ -2801,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,
@@ -2811,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()) {
@@ -2855,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);
@@ -2867,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;
@@ -2904,7 +3056,7 @@ static void GenerateVariantsOf(TreePatternNode *N,
return;
}
}
-
+
// Compute permutations of all children.
std::vector<std::vector<TreePatternNode*> > ChildVariants;
ChildVariants.resize(N->getNumChildren());
@@ -2956,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
@@ -2992,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) {
@@ -3013,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 0a1362a..946dcee 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 575852b..f37d3ea 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -28,15 +28,15 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
isPredicable = false;
hasOptionalDef = false;
isVariadic = false;
-
+
DagInit *OutDI = R->getValueAsDag("OutOperandList");
-
+
if (DefInit *Init = dynamic_cast<DefInit*>(OutDI->getOperator())) {
if (Init->getDef()->getName() != "outs")
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");
@@ -45,7 +45,7 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
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){
@@ -58,11 +58,11 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
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;
@@ -73,19 +73,19 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
// 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")
throw "Bad value for MIOperandInfo in operand '" + Rec->getName() +
"'\n";
-
+
// If we have MIOpInfo, then we have #operands equal to number of entries
// in MIOperandInfo.
if (unsigned NumArgs = MIOpInfo->getNumArgs())
NumOps = NumArgs;
-
+
if (Rec->isSubClassOf("PredicateOperand"))
isPredicable = true;
else if (Rec->isSubClassOf("OptionalDefOperand"))
@@ -94,10 +94,11 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
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!";
-
+
// Check that the operand has a name and that it's unique.
if (ArgName.empty())
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
@@ -105,13 +106,13 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
if (!OperandNames.insert(ArgName).second)
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
" has the same name as a previous operand!";
-
+
OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod, EncoderMethod,
MIOperandNo, NumOps, MIOpInfo));
MIOperandNo += NumOps;
}
-
-
+
+
// 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)
@@ -126,7 +127,7 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
unsigned CGIOperandList::getOperandNamed(StringRef Name) const {
unsigned OpIdx;
if (hasOperandNamed(Name, OpIdx)) return OpIdx;
- throw "'" + TheDef->getName() + "' does not have an operand named '$" +
+ throw "'" + TheDef->getName() + "' does not have an operand named '$" +
Name.str() + "'!";
}
@@ -147,10 +148,10 @@ std::pair<unsigned,unsigned>
CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) {
if (Op.empty() || Op[0] != '$')
throw TheDef->getName() + ": Illegal operand name: '" + Op + "'";
-
+
std::string OpName = Op.substr(1);
std::string SubOpName;
-
+
// Check to see if this is $foo.bar.
std::string::size_type DotIdx = OpName.find_first_of(".");
if (DotIdx != std::string::npos) {
@@ -159,30 +160,30 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) {
throw TheDef->getName() + ": illegal empty suboperand name in '" +Op +"'";
OpName = OpName.substr(0, DotIdx);
}
-
+
unsigned OpIdx = getOperandNamed(OpName);
-
+
if (SubOpName.empty()) { // If no suboperand name was specified:
// If one was needed, throw.
if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&
SubOpName.empty())
throw TheDef->getName() + ": Illegal to refer to"
" whole operand part of complex operand '" + Op + "'";
-
+
// Otherwise, return the operand.
return std::make_pair(OpIdx, 0U);
}
-
+
// Find the suboperand number involved.
DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo;
if (MIOpInfo == 0)
throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
-
+
// Find the operand with the right name.
for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i)
if (MIOpInfo->getArgName(i) == SubOpName)
return std::make_pair(OpIdx, i);
-
+
// Otherwise, didn't find it!
throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
}
@@ -199,7 +200,7 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) {
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!";
@@ -207,33 +208,33 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) {
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] =
@@ -242,16 +243,16 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) {
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);
}
@@ -262,16 +263,16 @@ void CGIOperandList::ProcessDisableEncoding(std::string DisableEncoding) {
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;
}
-
+
}
//===----------------------------------------------------------------------===//
@@ -286,6 +287,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) {
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");
@@ -324,11 +326,11 @@ CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) {
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];
@@ -341,7 +343,7 @@ HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
std::string CodeGenInstruction::
FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
std::string Res = "";
-
+
for (;;) {
// Find the start of the next variant string.
size_t VariantsStart = 0;
@@ -350,14 +352,14 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
(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;
@@ -368,18 +370,18 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
} 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;
}
@@ -388,6 +390,71 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
/// 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");
@@ -398,120 +465,73 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
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(), "result has " + utostr(Result->getNumArgs()) +
- " arguments, but " + ResultInst->TheDef->getName() +
- " instruction expects " +
- utostr(ResultInst->Operands.size()) + " operands!");
-
-
- Init *Arg = Result->getArg(AliasOpNo);
- Record *ResultOpRec = ResultInst->Operands[i].Rec;
-
- // Handle explicit registers.
- if (DefInit *ADI = dynamic_cast<DefInit*>(Arg)) {
- if (ADI->getDef()->isSubClassOf("Register")) {
- if (!Result->getArgName(AliasOpNo).empty())
- throw TGError(R->getLoc(), "result fixed register argument must "
- "not have a name!");
-
- if (!ResultOpRec->isSubClassOf("RegisterClass"))
- throw TGError(R->getLoc(), "result fixed register argument is not "
- "passed to a RegisterClass operand!");
-
- if (!T.getRegisterClass(ResultOpRec).containsRegister(ADI->getDef()))
- throw TGError(R->getLoc(), "fixed register " +ADI->getDef()->getName()
- + " is not a member of the " + ResultOpRec->getName() +
- " register class!");
-
- // Now that it is validated, add it.
- ResultOperands.push_back(ResultOperand(ADI->getDef()));
- ++AliasOpNo;
- continue;
- }
- }
-
- // 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 (DefInit *ADI = dynamic_cast<DefInit*>(Arg)) {
- if (Result->getArgName(AliasOpNo).empty())
- throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
- " must have a name!");
-
- if (ADI->getDef() != ResultOpRec)
- throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
- " declared with class " + ADI->getDef()->getName() +
- ", instruction operand is class " +
- ResultOpRec->getName());
-
- // 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(AliasOpNo)];
- if (Entry && Entry != ADI->getDef())
- throw TGError(R->getLoc(), "result value $" +
- Result->getArgName(AliasOpNo) +
- " is both " + Entry->getName() + " and " +
- ADI->getDef()->getName() + "!");
-
- // Now that it is validated, add it.
- ResultOperands.push_back(ResultOperand(Result->getArgName(AliasOpNo),
- ADI->getDef()));
+ 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 (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
- // Integer arguments can't have names.
- if (!Result->getArgName(AliasOpNo).empty())
- throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
- " must not have a name!");
- if (ResultInst->Operands[i].MINumOperands != 1 ||
- !ResultOpRec->isSubClassOf("Operand"))
- throw TGError(R->getLoc(), "invalid argument class " +
- ResultOpRec->getName() +
- " for integer result operand!");
- ResultOperands.push_back(ResultOperand(II->getValue()));
- ++AliasOpNo;
+
+ // 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 of inst alias has unknown operand type");
+ throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
+ " does not match instruction operand class " +
+ InstOpRec->getName());
}
-
- if (AliasOpNo != Result->getNumArgs())
- throw TGError(R->getLoc(), "result has " + utostr(Result->getNumArgs()) +
- " arguments, but " + ResultInst->TheDef->getName() +
- " instruction expects " + utostr(ResultInst->Operands.size())+
- " operands!");
-}
-/// getResultInstOperandIndexForResultOperandIndex - Given an index into the
-/// ResultOperands array, translate it to a valid index in ResultInst's
-/// operand list.
-unsigned CodeGenInstAlias::
-getResultInstOperandIndexForResultOperandIndex(unsigned OpNo) const {
- unsigned OpIdx = 0;
-
- for (unsigned i = 0;; ++i) {
- assert(i != ResultInst->Operands.size() && "Didn't find entry");
- if (ResultInst->Operands[i].getTiedRegister() != -1)
- continue;
-
- if (OpIdx == OpNo) return i;
-
- ++OpIdx;
- }
+ 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 9cd23e6..58913b9 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -16,6 +16,7 @@
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SourceMgr.h"
#include <string>
#include <vector>
#include <utility>
@@ -213,6 +214,7 @@ namespace llvm {
bool isBranch;
bool isIndirectBranch;
bool isCompare;
+ bool isMoveImm;
bool isBarrier;
bool isCall;
bool canFoldAsLoad;
@@ -295,13 +297,19 @@ namespace llvm {
/// 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);
-
- /// getResultInstOperandIndexForResultOperandIndex - Given an index into the
- /// ResultOperands array, translate it to a valid index in ResultInst's
- /// operand list.
- unsigned getResultInstOperandIndexForResultOperandIndex(unsigned i) const;
+
+ bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
+ Record *InstOpRec, bool hasSubOps, SMLoc Loc,
+ CodeGenTarget &T, ResultOperand &ResOp);
};
}
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index f8ba674..d0f7d8b 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -64,7 +64,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::f128: return "MVT::f128";
case MVT::ppcf128: return "MVT::ppcf128";
case MVT::x86mmx: return "MVT::x86mmx";
- case MVT::Flag: return "MVT::Flag";
+ case MVT::Glue: return "MVT::Glue";
case MVT::isVoid: return "MVT::isVoid";
case MVT::v2i8: return "MVT::v2i8";
case MVT::v4i8: return "MVT::v4i8";
@@ -108,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!");
@@ -314,7 +314,8 @@ void CodeGenTarget::ReadInstructions() const {
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
@@ -358,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);
@@ -403,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") {
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index 66cbce1..f1058eb 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -35,9 +35,9 @@ enum SDNP {
SDNPCommutative,
SDNPAssociative,
SDNPHasChain,
- SDNPOutFlag,
- SDNPInFlag,
- SDNPOptInFlag,
+ SDNPOutGlue,
+ SDNPInGlue,
+ SDNPOptInGlue,
SDNPMayLoad,
SDNPMayStore,
SDNPSideEffect,
@@ -61,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;
@@ -76,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;
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index 8a73404..dee8f77 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -27,7 +27,7 @@ using namespace llvm;
static unsigned getResultPatternCost(TreePatternNode *P,
CodeGenDAGPatterns &CGP) {
if (P->isLeaf()) return 0;
-
+
unsigned Cost = 0;
Record *Op = P->getOperator();
if (Op->isSubClassOf("Instruction")) {
@@ -43,7 +43,7 @@ static unsigned getResultPatternCost(TreePatternNode *P,
/// getResultPatternCodeSize - Compute the code size of instructions for this
/// pattern.
-static unsigned getResultPatternSize(TreePatternNode *P,
+static unsigned getResultPatternSize(TreePatternNode *P,
CodeGenDAGPatterns &CGP) {
if (P->isLeaf()) return 0;
@@ -64,21 +64,21 @@ namespace {
struct PatternSortingPredicate {
PatternSortingPredicate(CodeGenDAGPatterns &cgp) : CGP(cgp) {}
CodeGenDAGPatterns &CGP;
-
+
bool operator()(const PatternToMatch *LHS, const PatternToMatch *RHS) {
const TreePatternNode *LHSSrc = LHS->getSrcPattern();
const TreePatternNode *RHSSrc = RHS->getSrcPattern();
-
+
if (LHSSrc->getNumTypes() != 0 && RHSSrc->getNumTypes() != 0 &&
LHSSrc->getType(0) != RHSSrc->getType(0)) {
MVT::SimpleValueType V1 = LHSSrc->getType(0), V2 = RHSSrc->getType(0);
if (MVT(V1).isVector() != MVT(V2).isVector())
return MVT(V2).isVector();
-
+
if (MVT(V1).isFloatingPoint() != MVT(V2).isFloatingPoint())
return MVT(V2).isFloatingPoint();
}
-
+
// Otherwise, if the patterns might both match, sort based on complexity,
// which means that we prefer to match patterns that cover more nodes in the
// input over nodes that cover fewer.
@@ -86,18 +86,18 @@ struct PatternSortingPredicate {
unsigned RHSSize = RHS->getPatternComplexity(CGP);
if (LHSSize > RHSSize) return true; // LHS -> bigger -> less cost
if (LHSSize < RHSSize) return false;
-
+
// If the patterns have equal complexity, compare generated instruction cost
unsigned LHSCost = getResultPatternCost(LHS->getDstPattern(), CGP);
unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), CGP);
if (LHSCost < RHSCost) return true;
if (LHSCost > RHSCost) return false;
-
+
unsigned LHSPatSize = getResultPatternSize(LHS->getDstPattern(), CGP);
unsigned RHSPatSize = getResultPatternSize(RHS->getDstPattern(), CGP);
if (LHSPatSize < RHSPatSize) return true;
if (LHSPatSize > RHSPatSize) return false;
-
+
// Sort based on the UID of the pattern, giving us a deterministic ordering
// if all other sorting conditions fail.
assert(LHS == RHS || LHS->ID != RHS->ID);
@@ -110,7 +110,7 @@ struct PatternSortingPredicate {
void DAGISelEmitter::run(raw_ostream &OS) {
EmitSourceFileHeader("DAG Instruction Selector for the " +
CGP.getTargetInfo().getName() + " target", OS);
-
+
OS << "// *** NOTE: This file is #included into the middle of the target\n"
<< "// *** instruction selector class. These functions are really "
<< "methods.\n\n";
@@ -132,8 +132,8 @@ void DAGISelEmitter::run(raw_ostream &OS) {
// We want to process the matches in order of minimal cost. Sort the patterns
// so the least cost one is at the start.
std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate(CGP));
-
-
+
+
// Convert each variant of each pattern into a Matcher.
std::vector<Matcher*> PatternMatchers;
for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
@@ -144,12 +144,16 @@ void DAGISelEmitter::run(raw_ostream &OS) {
break;
}
}
-
+
Matcher *TheMatcher = new ScopeMatcher(&PatternMatchers[0],
PatternMatchers.size());
+ CodeGenTarget Target(Records);
+ const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
+ bool useEmitRegister2 = Registers.size() > 255;
+
TheMatcher = OptimizeMatcher(TheMatcher, CGP);
//Matcher->dump();
- EmitMatcherTable(TheMatcher, CGP, OS);
+ EmitMatcherTable(TheMatcher, CGP, useEmitRegister2, OS);
delete TheMatcher;
}
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index 9f12a68..2afa2b9 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 d9b25d5..d17051c 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -29,9 +29,9 @@ Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,unsigned Variant,
const CodeGenDAGPatterns &CGP);
Matcher *OptimizeMatcher(Matcher *Matcher, const CodeGenDAGPatterns &CGP);
void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP,
- raw_ostream &OS);
+ bool useEmitRegister2, 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 caba99b..3a71ddb 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -43,19 +43,22 @@ class MatcherTableEmitter {
DenseMap<Record*, unsigned> NodeXFormMap;
std::vector<Record*> NodeXForms;
+ bool useEmitRegister2;
+
public:
- MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) {}
+ MatcherTableEmitter(const CodeGenDAGPatterns &cgp, bool _useEmitRegister2)
+ : CGP(cgp), useEmitRegister2(_useEmitRegister2) {}
unsigned EmitMatcherList(const Matcher *N, unsigned Indent,
unsigned StartIdx, formatted_raw_ostream &OS);
-
+
void EmitPredicateFunctions(formatted_raw_ostream &OS);
-
+
void EmitHistogram(const Matcher *N, formatted_raw_ostream &OS);
private:
unsigned EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
formatted_raw_ostream &OS);
-
+
unsigned getNodePredicate(StringRef PredName) {
unsigned &Entry = NodePredicateMap[PredName];
if (Entry == 0) {
@@ -72,7 +75,7 @@ private:
}
return Entry-1;
}
-
+
unsigned getComplexPat(const ComplexPattern &P) {
unsigned &Entry = ComplexPatternMap[&P];
if (Entry == 0) {
@@ -81,7 +84,7 @@ private:
}
return Entry-1;
}
-
+
unsigned getNodeXFormID(Record *Rec) {
unsigned &Entry = NodeXFormMap[Rec];
if (Entry == 0) {
@@ -90,13 +93,13 @@ private:
}
return Entry-1;
}
-
+
};
} // end anonymous namespace.
static unsigned GetVBRSize(unsigned Val) {
if (Val <= 127) return 1;
-
+
unsigned NumBytes = 0;
while (Val >= 128) {
Val >>= 7;
@@ -112,7 +115,7 @@ static uint64_t EmitVBRValue(uint64_t Val, raw_ostream &OS) {
OS << Val << ", ";
return 1;
}
-
+
uint64_t InVal = Val;
unsigned NumBytes = 0;
while (Val >= 128) {
@@ -133,14 +136,14 @@ unsigned MatcherTableEmitter::
EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
formatted_raw_ostream &OS) {
OS.PadToColumn(Indent*2);
-
+
switch (N->getKind()) {
case Matcher::Scope: {
const ScopeMatcher *SM = cast<ScopeMatcher>(N);
assert(SM->getNext() == 0 && "Shouldn't have next after scope");
-
+
unsigned StartIdx = CurrentIdx;
-
+
// Emit all of the children.
for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) {
if (i == 0) {
@@ -164,29 +167,29 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
unsigned VBRSize = 0;
do {
VBRSize = GetVBRSize(ChildSize);
-
+
TmpBuf.clear();
raw_svector_ostream OS(TmpBuf);
formatted_raw_ostream FOS(OS);
ChildSize = EmitMatcherList(SM->getChild(i), Indent+1,
CurrentIdx+VBRSize, FOS);
} while (GetVBRSize(ChildSize) != VBRSize);
-
+
assert(ChildSize != 0 && "Should not have a zero-sized child!");
-
+
CurrentIdx += EmitVBRValue(ChildSize, OS);
if (!OmitComments) {
OS << "/*->" << CurrentIdx+ChildSize << "*/";
-
+
if (i == 0)
OS.PadToColumn(CommentIndent) << "// " << SM->getNumChildren()
<< " children in Scope";
}
-
+
OS << '\n' << TmpBuf.str();
CurrentIdx += ChildSize;
}
-
+
// Emit a zero as a sentinel indicating end of 'Scope'.
if (!OmitComments)
OS << "/*" << CurrentIdx << "*/";
@@ -196,7 +199,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << '\n';
return CurrentIdx - StartIdx + 1;
}
-
+
case Matcher::RecordNode:
OS << "OPC_RecordNode,";
if (!OmitComments)
@@ -215,23 +218,23 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
<< cast<RecordChildMatcher>(N)->getWhatFor();
OS << '\n';
return 1;
-
+
case Matcher::RecordMemRef:
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:
OS << "OPC_MoveChild, " << cast<MoveChildMatcher>(N)->getChildNo() << ",\n";
return 2;
-
+
case Matcher::MoveParent:
OS << "OPC_MoveParent,\n";
return 1;
-
+
case Matcher::CheckSame:
OS << "OPC_CheckSame, "
<< cast<CheckSameMatcher>(N)->getMatchNumber() << ",\n";
@@ -255,14 +258,14 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
}
case Matcher::CheckOpcode:
- OS << "OPC_CheckOpcode, TARGET_OPCODE("
+ OS << "OPC_CheckOpcode, TARGET_VAL("
<< cast<CheckOpcodeMatcher>(N)->getOpcode().getEnumName() << "),\n";
return 3;
-
+
case Matcher::SwitchOpcode:
case Matcher::SwitchType: {
unsigned StartIdx = CurrentIdx;
-
+
unsigned NumCases;
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) {
OS << "OPC_SwitchOpcode ";
@@ -276,7 +279,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << "/*" << NumCases << " cases */";
OS << ", ";
++CurrentIdx;
-
+
// For each case we emit the size, then the opcode, then the matcher.
for (unsigned i = 0, e = NumCases; i != e; ++i) {
const Matcher *Child;
@@ -288,7 +291,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
Child = cast<SwitchTypeMatcher>(N)->getCaseMatcher(i);
IdxSize = 1; // size of type in table is 1 byte.
}
-
+
// We need to encode the opcode and the offset of the case code before
// emitting the case code. Handle this by buffering the output into a
// string while we get the size. Unfortunately, the offset of the
@@ -299,29 +302,29 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
unsigned VBRSize = 0;
do {
VBRSize = GetVBRSize(ChildSize);
-
+
TmpBuf.clear();
raw_svector_ostream OS(TmpBuf);
formatted_raw_ostream FOS(OS);
ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+IdxSize,
FOS);
} while (GetVBRSize(ChildSize) != VBRSize);
-
+
assert(ChildSize != 0 && "Should not have a zero-sized child!");
-
+
if (i != 0) {
OS.PadToColumn(Indent*2);
if (!OmitComments)
OS << (isa<SwitchOpcodeMatcher>(N) ?
"/*SwitchOpcode*/ " : "/*SwitchType*/ ");
}
-
+
// Emit the VBR.
CurrentIdx += EmitVBRValue(ChildSize, OS);
-
+
OS << ' ';
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
- OS << "TARGET_OPCODE(" << SOM->getCaseOpcode(i).getEnumName() << "),";
+ OS << "TARGET_VAL(" << SOM->getCaseOpcode(i).getEnumName() << "),";
else
OS << getEnumName(cast<SwitchTypeMatcher>(N)->getCaseType(i)) << ',';
@@ -351,13 +354,13 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << "OPC_CheckType, "
<< getEnumName(cast<CheckTypeMatcher>(N)->getType()) << ",\n";
return 2;
-
+
case Matcher::CheckChildType:
OS << "OPC_CheckChild"
<< cast<CheckChildTypeMatcher>(N)->getChildNo() << "Type, "
<< getEnumName(cast<CheckChildTypeMatcher>(N)->getType()) << ",\n";
return 2;
-
+
case Matcher::CheckInteger: {
OS << "OPC_CheckInteger, ";
unsigned Bytes=1+EmitVBRValue(cast<CheckIntegerMatcher>(N)->getValue(), OS);
@@ -368,7 +371,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << "OPC_CheckCondCode, ISD::"
<< cast<CheckCondCodeMatcher>(N)->getCondCodeName() << ",\n";
return 2;
-
+
case Matcher::CheckValueType:
OS << "OPC_CheckValueType, MVT::"
<< cast<CheckValueTypeMatcher>(N)->getTypeName() << ",\n";
@@ -379,20 +382,20 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
const ComplexPattern &Pattern = CCPM->getPattern();
OS << "OPC_CheckComplexPat, /*CP*/" << getComplexPat(Pattern) << ", /*#*/"
<< CCPM->getMatchNumber() << ',';
-
+
if (!OmitComments) {
OS.PadToColumn(CommentIndent) << "// " << Pattern.getSelectFunc();
OS << ":$" << CCPM->getName();
for (unsigned i = 0, e = Pattern.getNumOperands(); i != e; ++i)
OS << " #" << CCPM->getFirstResult()+i;
-
+
if (Pattern.hasProperty(SDNPHasChain))
OS << " + chain result";
}
OS << '\n';
return 3;
}
-
+
case Matcher::CheckAndImm: {
OS << "OPC_CheckAndImm, ";
unsigned Bytes=1+EmitVBRValue(cast<CheckAndImmMatcher>(N)->getValue(), OS);
@@ -406,11 +409,11 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << '\n';
return Bytes;
}
-
+
case Matcher::CheckFoldableChainNode:
OS << "OPC_CheckFoldableChainNode,\n";
return 1;
-
+
case Matcher::EmitInteger: {
int64_t Val = cast<EmitIntegerMatcher>(N)->getValue();
OS << "OPC_EmitInteger, "
@@ -427,35 +430,49 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
<< Val << ",\n";
return 3;
}
-
+
case Matcher::EmitRegister:
- OS << "OPC_EmitRegister, "
- << getEnumName(cast<EmitRegisterMatcher>(N)->getVT()) << ", ";
- if (Record *R = cast<EmitRegisterMatcher>(N)->getReg())
- OS << getQualifiedName(R) << ",\n";
- else {
- OS << "0 ";
- if (!OmitComments)
- OS << "/*zero_reg*/";
- OS << ",\n";
+ if (useEmitRegister2) {
+ OS << "OPC_EmitRegister2, "
+ << getEnumName(cast<EmitRegisterMatcher>(N)->getVT()) << ", ";
+ if (Record *R = cast<EmitRegisterMatcher>(N)->getReg())
+ OS << "TARGET_VAL(" << getQualifiedName(R) << "),\n";
+ else {
+ OS << "TARGET_VAL(0) ";
+ if (!OmitComments)
+ OS << "/*zero_reg*/";
+ OS << ",\n";
+ }
+ return 4;
+ } else {
+ OS << "OPC_EmitRegister, "
+ << getEnumName(cast<EmitRegisterMatcher>(N)->getVT()) << ", ";
+ if (Record *R = cast<EmitRegisterMatcher>(N)->getReg())
+ OS << getQualifiedName(R) << ",\n";
+ else {
+ OS << "0 ";
+ if (!OmitComments)
+ OS << "/*zero_reg*/";
+ OS << ",\n";
+ }
+ return 3;
}
- return 3;
-
+
case Matcher::EmitConvertToTarget:
OS << "OPC_EmitConvertToTarget, "
<< cast<EmitConvertToTargetMatcher>(N)->getSlot() << ",\n";
return 2;
-
+
case Matcher::EmitMergeInputChains: {
const EmitMergeInputChainsMatcher *MN =
cast<EmitMergeInputChainsMatcher>(N);
-
+
// Handle the specialized forms OPC_EmitMergeInputChains1_0 and 1_1.
if (MN->getNumNodes() == 1 && MN->getNode(0) < 2) {
OS << "OPC_EmitMergeInputChains1_" << MN->getNode(0) << ",\n";
return 1;
}
-
+
OS << "OPC_EmitMergeInputChains, " << MN->getNumNodes() << ", ";
for (unsigned i = 0, e = MN->getNumNodes(); i != e; ++i)
OS << MN->getNode(i) << ", ";
@@ -477,21 +494,21 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS <<'\n';
return 3;
}
-
+
case Matcher::EmitNode:
case Matcher::MorphNodeTo: {
const EmitNodeMatcherCommon *EN = cast<EmitNodeMatcherCommon>(N);
OS << (isa<EmitNodeMatcher>(EN) ? "OPC_EmitNode" : "OPC_MorphNodeTo");
- OS << ", TARGET_OPCODE(" << EN->getOpcodeName() << "), 0";
-
+ OS << ", TARGET_VAL(" << 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();
OS << ",\n";
-
+
OS.PadToColumn(Indent*2+4) << EN->getNumVTs();
if (!OmitComments)
OS << "/*#VTs*/";
@@ -506,7 +523,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
unsigned NumOperandBytes = 0;
for (unsigned i = 0, e = EN->getNumOperands(); i != e; ++i)
NumOperandBytes += EmitVBRValue(EN->getOperand(i), OS);
-
+
if (!OmitComments) {
// Print the result #'s for EmitNode.
if (const EmitNodeMatcher *E = dyn_cast<EmitNodeMatcher>(EN)) {
@@ -521,19 +538,19 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
if (const MorphNodeToMatcher *SNT = dyn_cast<MorphNodeToMatcher>(N)) {
OS.PadToColumn(Indent*2) << "// Src: "
- << *SNT->getPattern().getSrcPattern() << " - Complexity = "
+ << *SNT->getPattern().getSrcPattern() << " - Complexity = "
<< SNT->getPattern().getPatternComplexity(CGP) << '\n';
OS.PadToColumn(Indent*2) << "// Dst: "
<< *SNT->getPattern().getDstPattern() << '\n';
}
} else
OS << '\n';
-
+
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);
@@ -549,7 +566,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << '\n';
if (!OmitComments) {
OS.PadToColumn(Indent*2) << "// Src: "
- << *CM->getPattern().getSrcPattern() << " - Complexity = "
+ << *CM->getPattern().getSrcPattern() << " - Complexity = "
<< CM->getPattern().getPatternComplexity(CGP) << '\n';
OS.PadToColumn(Indent*2) << "// Dst: "
<< *CM->getPattern().getDstPattern();
@@ -573,7 +590,7 @@ EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
unsigned MatcherSize = EmitMatcher(N, Indent, CurrentIdx, OS);
Size += MatcherSize;
CurrentIdx += MatcherSize;
-
+
// If there are other nodes in this list, iterate to them, otherwise we're
// done.
N = N->getNext();
@@ -592,15 +609,15 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
OS << " }\n";
OS << "}\n\n";
}
-
+
// Emit Node predicates.
// FIXME: Annoyingly, these are stored by name, which we never even emit. Yay?
StringMap<TreePattern*> PFsByName;
-
+
for (CodeGenDAGPatterns::pf_iterator I = CGP.pf_begin(), E = CGP.pf_end();
I != E; ++I)
PFsByName[I->first->getName()] = I->second;
-
+
if (!NodePredicates.empty()) {
OS << "bool CheckNodePredicate(SDNode *Node, unsigned PredNo) const {\n";
OS << " switch (PredNo) {\n";
@@ -609,7 +626,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
// FIXME: Storing this by name is horrible.
TreePattern *P =PFsByName[NodePredicates[i].substr(strlen("Predicate_"))];
assert(P && "Unknown name?");
-
+
// Emit the predicate code corresponding to this pattern.
std::string Code = P->getRecord()->getValueAsCode("Predicate");
assert(!Code.empty() && "No code in this predicate");
@@ -629,7 +646,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
OS << " }\n";
OS << "}\n\n";
}
-
+
// Emit CompletePattern matchers.
// FIXME: This should be const.
if (!ComplexPatterns.empty()) {
@@ -645,7 +662,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
if (P.hasProperty(SDNPHasChain))
++NumOps; // Get the chained node too.
-
+
OS << " case " << i << ":\n";
OS << " Result.resize(NextRes+" << NumOps << ");\n";
OS << " return " << P.getSelectFunc();
@@ -655,12 +672,12 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
// 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 << "].first";
@@ -669,28 +686,28 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
OS << " }\n";
OS << "}\n\n";
}
-
-
+
+
// Emit SDNodeXForm handlers.
// FIXME: This should be const.
if (!NodeXForms.empty()) {
OS << "SDValue RunSDNodeXForm(SDValue V, unsigned XFormNo) {\n";
OS << " switch (XFormNo) {\n";
OS << " default: assert(0 && \"Invalid xform # in table?\");\n";
-
+
// FIXME: The node xform could take SDValue's instead of SDNode*'s.
for (unsigned i = 0, e = NodeXForms.size(); i != e; ++i) {
const CodeGenDAGPatterns::NodeXForm &Entry =
CGP.getSDNodeTransform(NodeXForms[i]);
-
+
Record *SDNode = Entry.first;
const std::string &Code = Entry.second;
-
+
OS << " case " << i << ": { ";
if (!OmitComments)
OS << "// " << NodeXForms[i]->getName();
OS << '\n';
-
+
std::string ClassName = CGP.getSDNodeInfo(SDNode).getSDClassName();
if (ClassName == "SDNode")
OS << " SDNode *N = V.getNode();\n";
@@ -710,12 +727,12 @@ static void BuildHistogram(const Matcher *M, std::vector<unsigned> &OpcodeFreq){
if (unsigned(M->getKind()) >= OpcodeFreq.size())
OpcodeFreq.resize(M->getKind()+1);
OpcodeFreq[M->getKind()]++;
-
+
// Handle recursive nodes.
if (const ScopeMatcher *SM = dyn_cast<ScopeMatcher>(M)) {
for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i)
BuildHistogram(SM->getChild(i), OpcodeFreq);
- } else if (const SwitchOpcodeMatcher *SOM =
+ } else if (const SwitchOpcodeMatcher *SOM =
dyn_cast<SwitchOpcodeMatcher>(M)) {
for (unsigned i = 0, e = SOM->getNumCases(); i != e; ++i)
BuildHistogram(SOM->getCaseMatcher(i), OpcodeFreq);
@@ -730,19 +747,19 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
formatted_raw_ostream &OS) {
if (OmitComments)
return;
-
+
std::vector<unsigned> OpcodeFreq;
BuildHistogram(M, OpcodeFreq);
-
+
OS << " // Opcode Histogram:\n";
for (unsigned i = 0, e = OpcodeFreq.size(); i != e; ++i) {
OS << " // #";
switch ((Matcher::KindTy)i) {
- case Matcher::Scope: OS << "OPC_Scope"; break;
- case Matcher::RecordNode: OS << "OPC_RecordNode"; break;
+ case Matcher::Scope: OS << "OPC_Scope"; break;
+ 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;
@@ -771,10 +788,10 @@ 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::CompleteMatch: OS << "OPC_CompleteMatch"; break;
+ case Matcher::MarkGlueResults: OS << "OPC_MarkGlueResults"; break;
+ case Matcher::CompleteMatch: OS << "OPC_CompleteMatch"; break;
}
-
+
OS.PadToColumn(40) << " = " << OpcodeFreq[i] << '\n';
}
OS << '\n';
@@ -782,26 +799,29 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
void llvm::EmitMatcherTable(const Matcher *TheMatcher,
- const CodeGenDAGPatterns &CGP, raw_ostream &O) {
+ const CodeGenDAGPatterns &CGP,
+ bool useEmitRegister2,
+ raw_ostream &O) {
formatted_raw_ostream OS(O);
-
+
OS << "// The main instruction selector code.\n";
OS << "SDNode *SelectCode(SDNode *N) {\n";
- MatcherTableEmitter MatcherEmitter(CGP);
+ MatcherTableEmitter MatcherEmitter(CGP, useEmitRegister2);
- OS << " // Opcodes are emitted as 2 bytes, TARGET_OPCODE handles this.\n";
- OS << " #define TARGET_OPCODE(X) X & 255, unsigned(X) >> 8\n";
+ OS << " // Some target values are emitted as 2 bytes, TARGET_VAL handles\n";
+ OS << " // this.\n";
+ OS << " #define TARGET_VAL(X) X & 255, unsigned(X) >> 8\n";
OS << " static const unsigned char MatcherTable[] = {\n";
unsigned TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 5, 0, OS);
OS << " 0\n }; // Total Array size is " << (TotalSize+1) << " bytes\n\n";
-
+
MatcherEmitter.EmitHistogram(TheMatcher, OS);
-
- OS << " #undef TARGET_OPCODE\n";
+
+ OS << " #undef TARGET_VAL\n";
OS << " return SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n}\n";
OS << '\n';
-
+
// Next up, emit the function for node and pattern predicates:
MatcherEmitter.EmitPredicateFunctions(OS);
}
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index c1e3212..7c0bade 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,39 +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; }
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];
@@ -123,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,
@@ -135,7 +135,7 @@ namespace {
void EmitResultSDNodeXFormAsOperand(const TreePatternNode *N,
SmallVectorImpl<unsigned> &ResultOps);
};
-
+
} // end anon namespace.
MatcherGen::MatcherGen(const PatternToMatch &pattern,
@@ -156,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();
}
@@ -169,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)
@@ -182,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);
@@ -199,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
@@ -212,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.
@@ -229,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.
@@ -256,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();
}
@@ -265,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
@@ -276,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()) {
@@ -302,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;
@@ -321,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;
@@ -352,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 =
@@ -365,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.
@@ -409,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()) {
@@ -434,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]));
@@ -462,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;
@@ -491,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)) {
@@ -507,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;
}
@@ -529,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)) {
@@ -540,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)
@@ -561,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")) {
@@ -582,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")) {
@@ -606,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)
@@ -625,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;
}
@@ -640,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.
//
@@ -649,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
@@ -680,7 +680,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
SmallVector<unsigned, 8> InstOps;
for (unsigned ChildNo = 0, InstOpNo = NumResults, e = II.Operands.size();
InstOpNo != e; ++InstOpNo) {
-
+
// Determine what to emit for this operand.
Record *OperandNode = II.Operands[InstOpNo].Rec;
if ((OperandNode->isSubClassOf("PredicateOperand") ||
@@ -689,30 +689,30 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// 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
@@ -720,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 ...))
@@ -743,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;
@@ -758,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.
@@ -775,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++);
}
}
@@ -799,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.
@@ -838,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);
@@ -846,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,
@@ -864,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));
}
@@ -895,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 c73bdb9..3169ea1 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 3284366..90a2af2 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 78d3510..b3deb84 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -322,8 +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;
}
@@ -353,7 +357,8 @@ static void X86PopulateOperands(
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 name: " << inst.TheDef->getName().c_str() << "\n";
@@ -563,9 +568,16 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
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");
@@ -581,11 +593,27 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
IMM("jt2block_operand");
IMM("t_imm_s4");
IMM("pclabel");
+ IMM("adrlabel");
+ IMM("t_adrlabel");
+ IMM("t2adrlabel");
IMM("shift_imm");
IMM("neon_vcvt_imm32");
+ IMM("nsr16_imm");
+ IMM("nsr32_imm");
+ IMM("nsr64_imm");
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
@@ -605,8 +633,11 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
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
@@ -616,11 +647,15 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
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;
}
@@ -823,13 +858,15 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
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");
@@ -866,7 +903,7 @@ void EDEmitter::run(raw_ostream &o) {
unsigned int i = 0;
CompoundConstantEmitter infoArray;
- CodeGenTarget target;
+ CodeGenTarget target(Records);
populateInstInfo(infoArray, target);
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index 0039506..f01de1d 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;
@@ -265,7 +266,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op);
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) {
@@ -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 0000000..2c222b3
--- /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 0000000..d46a495
--- /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 47a8474..aa59689 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 e04ab6c..2b684be 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -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)";
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index b7ac85c..c40a39d 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -768,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);
}
@@ -3028,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);
@@ -3089,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 b37b83f..0f2ff37 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 f27cd99..c01b660 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 f3707f2..64224d9 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,184 +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;
- if (op == OpHi || op == OpLo) {
- s = "union { " + ts + " r; double d; } u; u.d";
- } else {
- s = ts + " r; r";
- if (structTypes)
- s += ".val";
+ if (!define) {
+ s = "return ";
}
-
- 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";
-
+
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_float64x2_t)" + a + ")[1])";
+ s += "(" + ts +
+ ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);";
break;
case OpLo:
- s += "(((__neon_float64x2_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;
}
- if (op == OpHi || op == OpLo)
- s += "; return u.r;";
- else
- s += "; return r;";
return s;
}
@@ -695,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);
@@ -706,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':
@@ -734,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 {
@@ -804,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 += ", ";
}
@@ -823,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";
@@ -902,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.
@@ -912,110 +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 && v == 1)
- 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";
- OS << "typedef __attribute__(( __vector_size__(8) )) "
- "double __neon_float64x1_t;\n";
- OS << "typedef __attribute__(( __vector_size__(16) )) "
- "double __neon_float64x2_t;\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;
@@ -1043,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) {
@@ -1053,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
@@ -1076,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) {
@@ -1090,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]);
@@ -1127,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);
@@ -1194,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]) {
@@ -1211,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 6c6760d..1e6fcbf 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 3d4e138..abbbafe 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;
}
@@ -528,7 +580,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
}
}
- if (Record *D = Records.getDef(Name))
+ if (Record *D = (CurRec->getRecords()).getDef(Name))
return new DefInit(D);
errs() << "Variable not defined: '" + Name + "'\n";
@@ -538,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) {
@@ -549,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) {
@@ -562,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) {
@@ -598,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() + ")";
}
@@ -966,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());
@@ -982,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]);
@@ -1135,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;
@@ -1227,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);
}
}
@@ -1497,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 44d64ab..f3a5df2 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;
@@ -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,10 +1230,15 @@ 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() {}
@@ -1315,6 +1323,10 @@ public:
/// possible references.
void resolveReferencesTo(const RecordVal *RV);
+ RecordKeeper &getRecords() const {
+ return TrackedRecords;
+ }
+
void dump() 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,8 +1500,6 @@ public:
raw_ostream &operator<<(raw_ostream &OS, const RecordKeeper &RK);
-extern RecordKeeper Records;
-
void PrintError(SMLoc ErrorLoc, const Twine &Msg);
} // End llvm namespace
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 6f06705..96399a4 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/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 754635b..e35bdca 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -638,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/TGLexer.cpp b/utils/TableGen/TGLexer.cpp
index 12fa39f..82d2b64 100644
--- a/utils/TableGen/TGLexer.cpp
+++ b/utils/TableGen/TGLexer.cpp
@@ -12,10 +12,11 @@
//===----------------------------------------------------------------------===//
#include "TGLexer.h"
-#include "llvm/ADT/Twine.h"
#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>
@@ -412,29 +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 == 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 f5753a4..55a6c5d 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>
@@ -46,7 +46,7 @@ namespace tgtok {
// !keywords.
XConcat, XSRA, XSRL, XSHL, XStrConcat, XCast, XSubst,
- XForEach, XCar, XCdr, XNull, XIf, XEq,
+ XForEach, XHead, XTail, XEmpty, XIf, XEq,
// Integer value.
IntVal,
diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp
index 22afca1..f6041be 100644
--- a/utils/TableGen/TGParser.cpp
+++ b/utils/TableGen/TGParser.cpp
@@ -683,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;
@@ -704,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;
}
@@ -727,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);
@@ -746,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;
@@ -764,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());
@@ -776,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;
@@ -868,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) {
@@ -919,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;
@@ -1068,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;
@@ -1243,9 +1273,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) {
return new DagInit(Operator, OperatorName, DagArgs);
}
- 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:
@@ -1632,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.
@@ -1699,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.
@@ -1816,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.
@@ -1945,7 +1976,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
}
}
- Record *CurRec = new Record(DefName, DefmPrefixLoc);
+ Record *CurRec = new Record(DefName, DefmPrefixLoc, Records);
SubClassReference Ref;
Ref.RefLoc = DefmPrefixLoc;
diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h
index 6e16522..9cdf68f 100644
--- a/utils/TableGen/TGParser.h
+++ b/utils/TableGen/TGParser.h
@@ -22,6 +22,7 @@
namespace llvm {
class Record;
class RecordVal;
+ class RecordKeeper;
struct RecTy;
struct Init;
struct MultiClass;
@@ -47,8 +48,12 @@ 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.
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 0bf6460..3b7dc01 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/ToolOutputFile.h"
-#include "llvm/System/Signals.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstdio>
using namespace llvm;
@@ -64,6 +67,7 @@ enum ActionType {
GenClangDiagGroups,
GenClangDeclNodes,
GenClangStmtNodes,
+ GenClangSACheckers,
GenDAGISel,
GenFastISel,
GenOptParserDefs, GenOptParserImpl,
@@ -74,6 +78,7 @@ enum ActionType {
GenEDInfo,
GenArmNeon,
GenArmNeonSema,
+ GenArmNeonTest,
PrintEnums
};
@@ -135,9 +140,11 @@ namespace {
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",
@@ -146,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));
@@ -172,9 +181,6 @@ namespace {
}
-// FIXME: Eliminate globals from tblgen.
-RecordKeeper llvm::Records;
-
static SourceMgr SrcMgr;
void llvm::PrintError(SMLoc ErrorLoc, const Twine &Msg) {
@@ -187,14 +193,15 @@ void llvm::PrintError(SMLoc ErrorLoc, const Twine &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());
@@ -203,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;
@@ -293,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;
@@ -329,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/X86ModRMFilters.h b/utils/TableGen/X86ModRMFilters.h
index 45cb07a..199040b 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 e3cad1a..b0839c3 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -34,7 +34,9 @@ using namespace llvm;
MAP(E8, 39) \
MAP(F0, 40) \
MAP(F8, 41) \
- MAP(F9, 42)
+ MAP(F9, 42) \
+ MAP(D0, 45) \
+ MAP(D1, 46)
// A clone of X86 since we can't depend on something that is generated.
namespace X86Local {
@@ -857,6 +859,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)
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 113b3bd..c043b90 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 {
diff --git a/utils/Target/ARM/analyze-match-table.py b/utils/Target/ARM/analyze-match-table.py
new file mode 100644
index 0000000..aa952d4
--- /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/GNUmakefile b/utils/buildit/GNUmakefile
index 54577e2..5140e15 100644
--- a/utils/buildit/GNUmakefile
+++ b/utils/buildit/GNUmakefile
@@ -80,6 +80,10 @@ EmbeddedSim:
export MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`; \
$(MAKE) IOS_SIM_BUILD=yes PREFIX=$(SDKROOT)/usr/local install
+Embedded:
+ ARM_PLATFORM=`xcodebuild -version -sdk iphoneos PlatformPath` && \
+ $(MAKE) DSTROOT=$(DSTROOT)$$ARM_PLATFORM install
+
# installhdrs does nothing, because the headers aren't useful until
# the compiler is installed.
installhdrs:
@@ -128,4 +132,4 @@ clean:
$(OBJROOT) $(SYMROOT) $(DSTROOT):
mkdir -p $@
-.PHONY: install installsrc clean EmbeddedHosted EmbeddedSim
+.PHONY: install installsrc clean EmbeddedHosted EmbeddedSim Embedded
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
index 122650a..38b0bfd 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.
@@ -272,8 +267,9 @@ fi
# 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
+# (The wildcards are used to match a "lib" prefix if it is present.)
+rm $DEST_DIR$DEST_ROOT/lib/*LLVMHello.dylib
+rm $DEST_DIR$DEST_ROOT/lib/*BugpointPasses.dylib
# Compress manpages
MDIR=$DEST_DIR$DEST_ROOT/share/man/man1
@@ -346,6 +342,9 @@ else
fi
rm -f lib/libLTO.a lib/libLTO.la
+# Omit lto.h from the result. Clang will supply.
+find $DEST_DIR$DEST_ROOT -name lto.h -delete
+
################################################################################
# Remove debugging information from DEST_DIR.
diff --git a/utils/count/CMakeLists.txt b/utils/count/CMakeLists.txt
index e124f61..4e0d371 100644
--- a/utils/count/CMakeLists.txt
+++ b/utils/count/CMakeLists.txt
@@ -1,3 +1,3 @@
-add_executable(count
+add_llvm_utility(count
count.c
)
diff --git a/utils/fpcmp/Makefile b/utils/fpcmp/Makefile
index fd2f747..81db3b9 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/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py
index 43ed6f1..7ca1b9c 100644
--- a/utils/lit/lit/LitConfig.py
+++ b/utils/lit/lit/LitConfig.py
@@ -85,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/TestFormats.py b/utils/lit/lit/TestFormats.py
index 7662e14..6dda2fd 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).split(';')
+ 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'.
@@ -59,8 +59,9 @@ 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 not filename in 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):
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index a2f97cd..80d0ba1 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
@@ -335,23 +337,28 @@ def executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd):
return out, err, exitCode
def executeScript(test, litConfig, tmpBase, commands, cwd):
+ bashPath = litConfig.getBashPath();
+ isWin32CMDEXE = (litConfig.isWindows and not bashPath)
script = tmpBase + '.script'
- if litConfig.isWindows:
+ if isWin32CMDEXE:
script += '.bat'
# Write script file
f = open(script,'w')
- if litConfig.isWindows:
+ if isWin32CMDEXE:
f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
else:
f.write(' &&\n'.join(commands))
f.write('\n')
f.close()
- if litConfig.isWindows:
+ if isWin32CMDEXE:
command = ['cmd','/c', script]
else:
- command = ['/bin/sh', script]
+ if bashPath:
+ command = [bashPath, script]
+ else:
+ command = ['/bin/sh', script]
if litConfig.useValgrind:
# FIXME: Running valgrind on sh is overkill. We probably could just
# run on clang with no real loss.
@@ -444,11 +451,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()
@@ -547,7 +558,7 @@ def executeShTest(test, litConfig, useExternalSh):
if test.config.unsupported:
return (Test.UNSUPPORTED, 'Test is unsupported')
- res = parseIntegratedTestScript(test)
+ res = parseIntegratedTestScript(test, useExternalSh)
if len(res) == 2:
return res
diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py
index 440375a..c7a03dd 100644
--- a/utils/lit/lit/TestingConfig.py
+++ b/utils/lit/lit/TestingConfig.py
@@ -17,6 +17,8 @@ class TestingConfig:
'PATHEXT' : os.environ.get('PATHEXT',''),
'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''),
'LLVM_DISABLE_CRT_DEBUG' : '1',
+ 'PRINTF_EXPONENT_DIGITS' : '2',
+ 'PYTHONUNBUFFERED' : '1',
}
config = TestingConfig(parent,
diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py
index 414b714..5635f50 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/llvm-lit/llvm-lit.in b/utils/llvm-lit/llvm-lit.in
index 3ff2c24..1df1747 100644..100755
--- 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/llvmbuild b/utils/llvmbuild
new file mode 100755
index 0000000..5912c50
--- /dev/null
+++ b/utils/llvmbuild
@@ -0,0 +1,749 @@
+#!/usr/bin/python3
+##===- utils/llvmbuild - Build the LLVM project ----------------*-python-*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script builds many different flavors of the LLVM ecosystem. It
+# will build LLVM, Clang, llvm-gcc, and dragonegg as well as run tests
+# on them. This script is convenient to use to check builds and tests
+# before committing changes to the upstream repository
+#
+# A typical source setup uses three trees and looks like this:
+#
+# official
+# dragonegg
+# trunk
+# gcc
+# trunk
+# llvm
+# trunk
+# tools
+# clang
+# tags
+# RELEASE_28
+# tools
+# clang
+# llvm-gcc
+# trunk
+# tags
+# RELEASE_28
+# staging
+# dragonegg
+# trunk
+# gcc
+# trunk
+# llvm
+# trunk
+# tools
+# clang
+# tags
+# RELEASE_28
+# tools
+# clang
+# llvm-gcc
+# trunk
+# tags
+# RELEASE_28
+# commit
+# dragonegg
+# trunk
+# gcc
+# trunk
+# llvm
+# trunk
+# tools
+# clang
+# tags
+# RELEASE_28
+# tools
+# clang
+# llvm-gcc
+# trunk
+# tags
+# RELEASE_28
+#
+# "gcc" above is the upstream FSF gcc and "gcc/trunk" refers to the
+# 4.5 branch as discussed in the dragonegg build guide.
+#
+# In a typical workflow, the "official" tree always contains unchanged
+# sources from the main LLVM project repositories. The "staging" tree
+# is where local work is done. A set of changes resides there waiting
+# to be moved upstream. The "commit" tree is where changes from
+# "staging" make their way upstream. Individual incremental changes
+# from "staging" are applied to "commit" and committed upstream after
+# a successful build and test run. A successful build is one in which
+# testing results in no more failures than seen in the testing of the
+# "official" tree.
+#
+# A build may be invoked as such:
+#
+# llvmbuild --src=~/llvm/commit --src=~/llvm/staging
+# --src=~/llvm/official --branch=trunk --branch=tags/RELEASE_28
+# --build=debug --build=release --build=paranoid
+# --prefix=/home/greened/install --builddir=/home/greened/build
+#
+# This will build the LLVM ecosystem, including LLVM, Clang, llvm-gcc,
+# gcc 4.5 and dragonegg, putting build results in ~/build and
+# installing tools in ~/install. llvmbuild creates separate build and
+# install directories for each source/branch/build flavor. In the
+# above example, llvmbuild will build debug, release and paranoid
+# (debug+checks) flavors of the trunk and RELEASE_28 branches from
+# each source tree (official, staging and commit) for a total of
+# eighteen builds. All builds will be run in parallel.
+#
+# The user may control parallelism via the --jobs and --threads
+# switches. --jobs tells llvmbuild the maximum total number of builds
+# to activate in parallel. The user may think of it as equivalent to
+# the GNU make -j switch. --threads tells llvmbuild how many worker
+# threads to use to accomplish those builds. If --threads is less
+# than --jobs, --threads workers will be launched and each one will
+# pick a source/branch/flavor combination to build. Then llvmbuild
+# will invoke GNU make with -j (--jobs / --threads) to use up the
+# remaining job capacity. Once a worker is finished with a build, it
+# will pick another combination off the list and start building it.
+#
+##===----------------------------------------------------------------------===##
+
+import optparse
+import os
+import sys
+import threading
+import queue
+import logging
+import traceback
+import subprocess
+import re
+
+# TODO: Use shutil.which when it is available (3.2 or later)
+def find_executable(executable, path=None):
+ """Try to find 'executable' in the directories listed in 'path' (a
+ string listing directories separated by 'os.pathsep'; defaults to
+ os.environ['PATH']). Returns the complete filename or None if not
+ found
+ """
+ if path is None:
+ path = os.environ['PATH']
+ paths = path.split(os.pathsep)
+ extlist = ['']
+ if os.name == 'os2':
+ (base, ext) = os.path.splitext(executable)
+ # executable files on OS/2 can have an arbitrary extension, but
+ # .exe is automatically appended if no dot is present in the name
+ if not ext:
+ executable = executable + ".exe"
+ elif sys.platform == 'win32':
+ pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
+ (base, ext) = os.path.splitext(executable)
+ if ext.lower() not in pathext:
+ extlist = pathext
+ for ext in extlist:
+ execname = executable + ext
+ if os.path.isfile(execname):
+ return execname
+ else:
+ for p in paths:
+ f = os.path.join(p, execname)
+ if os.path.isfile(f):
+ return f
+ else:
+ return None
+
+def is_executable(fpath):
+ return os.path.exists(fpath) and os.access(fpath, os.X_OK)
+
+def add_options(parser):
+ parser.add_option("-v", "--verbose", action="store_true",
+ default=False,
+ help=("Output informational messages"
+ " [default: %default]"))
+ parser.add_option("--src", action="append",
+ help=("Top-level source directory [default: %default]"))
+ parser.add_option("--build", action="append",
+ help=("Build types to run [default: %default]"))
+ parser.add_option("--branch", action="append",
+ help=("Source branch to build [default: %default]"))
+ parser.add_option("--cc", default=find_executable("cc"),
+ help=("The C compiler to use [default: %default]"))
+ parser.add_option("--cxx", default=find_executable("c++"),
+ help=("The C++ compiler to use [default: %default]"))
+ parser.add_option("--threads", default=4, type="int",
+ help=("The number of worker threads to use "
+ "[default: %default]"))
+ parser.add_option("--jobs", "-j", default=8, type="int",
+ help=("The number of simultaneous build jobs "
+ "[default: %default]"))
+ parser.add_option("--prefix",
+ help=("Root install directory [default: %default]"))
+ parser.add_option("--builddir",
+ help=("Root build directory [default: %default]"))
+ parser.add_option("--extra-llvm-config-flags", default="",
+ help=("Extra flags to pass to llvm configure [default: %default]"))
+ parser.add_option("--extra-llvm-gcc-config-flags", default="",
+ help=("Extra flags to pass to llvm-gcc configure [default: %default]"))
+ parser.add_option("--extra-gcc-config-flags", default="",
+ help=("Extra flags to pass to gcc configure [default: %default]"))
+ parser.add_option("--force-configure", default=False, action="store_true",
+ help=("Force reconfigure of all components"))
+ return
+
+def check_options(parser, options, valid_builds):
+ # See if we're building valid flavors.
+ for build in options.build:
+ if (build not in valid_builds):
+ parser.error("'" + build + "' is not a valid build flavor "
+ + str(valid_builds))
+
+ # See if we can find source directories.
+ for src in options.src:
+ for component in ["llvm", "llvm-gcc", "gcc", "dragonegg"]:
+ compsrc = src + "/" + component
+ if (not os.path.isdir(compsrc)):
+ parser.error("'" + compsrc + "' does not exist")
+ if (options.branch is not None):
+ for branch in options.branch:
+ if (not os.path.isdir(os.path.join(compsrc, branch))):
+ parser.error("'" + os.path.join(compsrc, branch)
+ + "' does not exist")
+
+ # See if we can find the compilers
+ options.cc = find_executable(options.cc)
+ options.cxx = find_executable(options.cxx)
+
+ return
+
+# Find a unique short name for the given set of paths. This searches
+# back through path components until it finds unique component names
+# among all given paths.
+def get_path_abbrevs(paths):
+ # Find the number of common starting characters in the last component
+ # of the paths.
+ unique_paths = list(paths)
+
+ class NotFoundException(Exception): pass
+
+ # Find a unique component of each path.
+ unique_bases = unique_paths[:]
+ found = 0
+ while len(unique_paths) > 0:
+ bases = [os.path.basename(src) for src in unique_paths]
+ components = { c for c in bases }
+ # Account for single entry in paths.
+ if len(components) > 1 or len(components) == len(bases):
+ # We found something unique.
+ for c in components:
+ if bases.count(c) == 1:
+ index = bases.index(c)
+ unique_bases[index] = c
+ # Remove the corresponding path from the set under
+ # consideration.
+ unique_paths[index] = None
+ unique_paths = [ p for p in unique_paths if p is not None ]
+ unique_paths = [os.path.dirname(src) for src in unique_paths]
+
+ if len(unique_paths) > 0:
+ raise NotFoundException()
+
+ abbrevs = dict(zip(paths, [base for base in unique_bases]))
+
+ return abbrevs
+
+# Given a set of unique names, find a short character sequence that
+# uniquely identifies them.
+def get_short_abbrevs(unique_bases):
+ # Find a unique start character for each path base.
+ my_unique_bases = unique_bases[:]
+ unique_char_starts = unique_bases[:]
+ while len(my_unique_bases) > 0:
+ for start, char_tuple in enumerate(zip(*[base
+ for base in my_unique_bases])):
+ chars = { c for c in char_tuple }
+ # Account for single path.
+ if len(chars) > 1 or len(chars) == len(char_tuple):
+ # We found something unique.
+ for c in chars:
+ if char_tuple.count(c) == 1:
+ index = char_tuple.index(c)
+ unique_char_starts[index] = start
+ # Remove the corresponding path from the set under
+ # consideration.
+ my_unique_bases[index] = None
+ my_unique_bases = [ b for b in my_unique_bases
+ if b is not None ]
+ break
+
+ if len(my_unique_bases) > 0:
+ raise NotFoundException()
+
+ abbrevs = [abbrev[start_index:start_index+3]
+ for abbrev, start_index
+ in zip([base for base in unique_bases],
+ [index for index in unique_char_starts])]
+
+ abbrevs = dict(zip(unique_bases, abbrevs))
+
+ return abbrevs
+
+class Builder(threading.Thread):
+ class ExecutableNotFound(Exception): pass
+ class FileNotExecutable(Exception): pass
+
+ def __init__(self, work_queue, jobs,
+ build_abbrev, source_abbrev, branch_abbrev,
+ options):
+ super().__init__()
+ self.work_queue = work_queue
+ self.jobs = jobs
+ self.cc = options.cc
+ self.cxx = options.cxx
+ self.build_abbrev = build_abbrev
+ self.source_abbrev = source_abbrev
+ self.branch_abbrev = branch_abbrev
+ self.build_prefix = options.builddir
+ self.install_prefix = options.prefix
+ self.options = options
+ self.component_abbrev = dict(
+ llvm="llvm",
+ llvm_gcc="lgcc",
+ llvm2="llv2",
+ gcc="ugcc",
+ dagonegg="degg")
+ def run(self):
+ while True:
+ try:
+ source, branch, build = self.work_queue.get()
+ self.dobuild(source, branch, build)
+ except:
+ traceback.print_exc()
+ finally:
+ self.work_queue.task_done()
+
+ def execute(self, command, execdir, env, component):
+ prefix = self.component_abbrev[component.replace("-", "_")]
+ pwd = os.getcwd()
+ if not os.path.exists(execdir):
+ os.makedirs(execdir)
+
+ execenv = os.environ.copy()
+
+ for key, value in env.items():
+ execenv[key] = value
+
+ self.logger.debug("[" + prefix + "] " + "env " + str(env) + " "
+ + " ".join(command));
+
+ try:
+ proc = subprocess.Popen(command,
+ cwd=execdir,
+ env=execenv,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ line = proc.stdout.readline()
+ while line:
+ self.logger.info("[" + prefix + "] "
+ + str(line, "utf-8").rstrip())
+ line = proc.stdout.readline()
+
+ except:
+ traceback.print_exc()
+
+ # Get a list of C++ include directories to pass to clang.
+ def get_includes(self):
+ # Assume we're building with g++ for now.
+ command = [self.cxx]
+ command += ["-v", "-x", "c++", "/dev/null", "-fsyntax-only"]
+ includes = []
+ self.logger.debug(command)
+ try:
+ proc = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ gather = False
+ line = proc.stdout.readline()
+ while line:
+ self.logger.debug(line)
+ if re.search("End of search list", str(line)) is not None:
+ self.logger.debug("Stop Gather")
+ gather = False
+ if gather:
+ includes.append(str(line, "utf-8").strip())
+ if re.search("#include <...> search starts", str(line)) is not None:
+ self.logger.debug("Start Gather")
+ gather = True
+ line = proc.stdout.readline()
+ except:
+ traceback.print_exc()
+ self.logger.debug(includes)
+ return includes
+
+ def dobuild(self, source, branch, build):
+ build_suffix = ""
+
+ ssabbrev = get_short_abbrevs([ab for ab in self.source_abbrev.values()])
+
+ if branch is not None:
+ sbabbrev = get_short_abbrevs([ab for ab in self.branch_abbrev.values()])
+
+ prefix = "[" + ssabbrev[self.source_abbrev[source]] + "-" + sbabbrev[self.branch_abbrev[branch]] + "-" + self.build_abbrev[build] + "]"
+ self.install_prefix += "/" + self.source_abbrev[source] + "/" + branch + "/" + build
+ build_suffix += self.source_abbrev[source] + "/" + branch + "/" + build
+ else:
+ prefix = "[" + ssabbrev[self.source_abbrev[source]] + "-" + self.build_abbrev[build] + "]"
+ self.install_prefix += "/" + self.source_abbrev[source] + "/" + build
+ build_suffix += "/" + self.source_abbrev[source] + "/" + build
+
+ self.logger = logging.getLogger(prefix)
+
+ self.logger.debug(self.install_prefix)
+
+ # Assume we're building with gcc for now.
+ cxxincludes = self.get_includes()
+ cxxroot = cxxincludes[0]
+ cxxarch = os.path.basename(cxxincludes[1])
+
+ configure_flags = dict(
+ llvm=dict(debug=["--prefix=" + self.install_prefix,
+ "--with-extra-options=-Werror",
+ "--with-cxx-include-root=" + cxxroot,
+ "--with-cxx-include-arch=" + cxxarch],
+ release=["--prefix=" + self.install_prefix,
+ "--with-extra-options=-Werror",
+ "--enable-optimized",
+ "--with-cxx-include-root=" + cxxroot,
+ "--with-cxx-include-arch=" + cxxarch],
+ paranoid=["--prefix=" + self.install_prefix,
+ "--with-extra-options=-Werror",
+ "--enable-expensive-checks",
+ "--with-cxx-include-root=" + cxxroot,
+ "--with-cxx-include-arch=" + cxxarch]),
+ llvm_gcc=dict(debug=["--prefix=" + self.install_prefix,
+ "--enable-checking",
+ "--program-prefix=llvm-",
+ "--enable-llvm=" + self.build_prefix + "/llvm/" + build_suffix,
+# Fortran install seems to be broken.
+# "--enable-languages=c,c++,fortran"],
+ "--enable-languages=c,c++"],
+ release=["--prefix=" + self.install_prefix,
+ "--program-prefix=llvm-",
+ "--enable-llvm=" + self.build_prefix + "/llvm/" + build_suffix,
+# Fortran install seems to be broken.
+# "--enable-languages=c,c++,fortran"],
+ "--enable-languages=c,c++"],
+ paranoid=["--prefix=" + self.install_prefix,
+ "--enable-checking",
+ "--program-prefix=llvm-",
+ "--enable-llvm=" + self.build_prefix + "/llvm/" + build_suffix,
+# Fortran install seems to be broken.
+# "--enable-languages=c,c++,fortran"]),
+ "--enable-languages=c,c++"]),
+ llvm2=dict(debug=["--prefix=" + self.install_prefix,
+ "--with-extra-options=-Werror",
+ "--with-llvmgccdir=" + self.install_prefix + "/bin",
+ "--with-cxx-include-root=" + cxxroot,
+ "--with-cxx-include-arch=" + cxxarch],
+ release=["--prefix=" + self.install_prefix,
+ "--with-extra-options=-Werror",
+ "--enable-optimized",
+ "--with-llvmgccdir=" + self.install_prefix + "/bin",
+ "--with-cxx-include-root=" + cxxroot,
+ "--with-cxx-include-arch=" + cxxarch],
+ paranoid=["--prefix=" + self.install_prefix,
+ "--with-extra-options=-Werror",
+ "--enable-expensive-checks",
+ "--with-llvmgccdir=" + self.install_prefix + "/bin",
+ "--with-cxx-include-root=" + cxxroot,
+ "--with-cxx-include-arch=" + cxxarch]),
+ gcc=dict(debug=["--prefix=" + self.install_prefix,
+ "--enable-checking"],
+ release=["--prefix=" + self.install_prefix],
+ paranoid=["--prefix=" + self.install_prefix,
+ "--enable-checking"]),
+ dragonegg=dict(debug=[],
+ release=[],
+ paranoid=[]))
+
+ configure_env = dict(
+ llvm=dict(debug=dict(CC=self.cc,
+ CXX=self.cxx),
+ release=dict(CC=self.cc,
+ CXX=self.cxx),
+ paranoid=dict(CC=self.cc,
+ CXX=self.cxx)),
+ llvm_gcc=dict(debug=dict(CC=self.cc,
+ CXX=self.cxx),
+ release=dict(CC=self.cc,
+ CXX=self.cxx),
+ paranoid=dict(CC=self.cc,
+ CXX=self.cxx)),
+ llvm2=dict(debug=dict(CC=self.cc,
+ CXX=self.cxx),
+ release=dict(CC=self.cc,
+ CXX=self.cxx),
+ paranoid=dict(CC=self.cc,
+ CXX=self.cxx)),
+ gcc=dict(debug=dict(CC=self.cc,
+ CXX=self.cxx),
+ release=dict(CC=self.cc,
+ CXX=self.cxx),
+ paranoid=dict(CC=self.cc,
+ CXX=self.cxx)),
+ dragonegg=dict(debug=dict(CC=self.cc,
+ CXX=self.cxx),
+ release=dict(CC=self.cc,
+ CXX=self.cxx),
+ paranoid=dict(CC=self.cc,
+ CXX=self.cxx)))
+
+ make_flags = dict(
+ llvm=dict(debug=["-j" + str(self.jobs)],
+ release=["-j" + str(self.jobs)],
+ paranoid=["-j" + str(self.jobs)]),
+ llvm_gcc=dict(debug=["-j" + str(self.jobs),
+ "bootstrap"],
+ release=["-j" + str(self.jobs),
+ "bootstrap"],
+ paranoid=["-j" + str(self.jobs),
+ "bootstrap"]),
+ llvm2=dict(debug=["-j" + str(self.jobs)],
+ release=["-j" + str(self.jobs)],
+ paranoid=["-j" + str(self.jobs)]),
+ gcc=dict(debug=["-j" + str(self.jobs),
+ "bootstrap"],
+ release=["-j" + str(self.jobs),
+ "bootstrap"],
+ paranoid=["-j" + str(self.jobs),
+ "bootstrap"]),
+ dragonegg=dict(debug=["-j" + str(self.jobs)],
+ release=["-j" + str(self.jobs)],
+ paranoid=["-j" + str(self.jobs)]))
+
+ make_env = dict(
+ llvm=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ llvm_gcc=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ llvm2=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ gcc=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ dragonegg=dict(debug=dict(GCC=self.install_prefix + "/bin/gcc",
+ LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"),
+ release=dict(GCC=self.install_prefix + "/bin/gcc",
+ LLVM_CONFIG=self.install_prefix + "/bin/llvm-config"),
+ paranoid=dict(GCC=self.install_prefix + "/bin/gcc",
+ LLVM_CONFIG=self.install_prefix + "/bin/llvm-config")))
+
+ make_install_flags = dict(
+ llvm=dict(debug=["install"],
+ release=["install"],
+ paranoid=["install"]),
+ llvm_gcc=dict(debug=["install"],
+ release=["install"],
+ paranoid=["install"]),
+ llvm2=dict(debug=["install"],
+ release=["install"],
+ paranoid=["install"]),
+ gcc=dict(debug=["install"],
+ release=["install"],
+ paranoid=["install"]),
+ dragonegg=dict(debug=["install"],
+ release=["install"],
+ paranoid=["install"]))
+
+ make_install_env = dict(
+ llvm=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ llvm_gcc=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ llvm2=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ gcc=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ dragonegg=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()))
+
+ make_check_flags = dict(
+ llvm=dict(debug=["check"],
+ release=["check"],
+ paranoid=["check"]),
+ llvm_gcc=dict(debug=["check"],
+ release=["check"],
+ paranoid=["check"]),
+ llvm2=dict(debug=["check"],
+ release=["check"],
+ paranoid=["check"]),
+ gcc=dict(debug=["check"],
+ release=["check"],
+ paranoid=["check"]),
+ dragonegg=dict(debug=["check"],
+ release=["check"],
+ paranoid=["check"]))
+
+ make_check_env = dict(
+ llvm=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ llvm_gcc=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ llvm2=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ gcc=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()),
+ dragonegg=dict(debug=dict(),
+ release=dict(),
+ paranoid=dict()))
+
+ for component in ["llvm", "llvm-gcc", "llvm2", "gcc", "dragonegg"]:
+ comp = component[:]
+
+ srcdir = source + "/" + comp.rstrip("2")
+ builddir = self.build_prefix + "/" + comp + "/" + build_suffix
+ installdir = self.install_prefix
+
+ if (branch is not None):
+ srcdir += "/" + branch
+
+ comp_key = comp.replace("-", "_")
+
+ config_args = configure_flags[comp_key][build][:]
+ config_args.extend(getattr(self.options,
+ "extra_" + comp_key
+ + "_config_flags").split())
+
+ self.logger.info("Configuring " + component + " in " + builddir)
+ self.configure(component, srcdir, builddir,
+ config_args,
+ configure_env[comp_key][build])
+
+ self.logger.info("Building " + component + " in " + builddir)
+ self.make(component, srcdir, builddir,
+ make_flags[comp_key][build],
+ make_env[comp_key][build])
+
+ self.logger.info("Installing " + component + " in " + installdir)
+ self.make(component, srcdir, builddir,
+ make_install_flags[comp_key][build],
+ make_install_env[comp_key][build])
+
+ self.logger.info("Testing " + component + " in " + builddir)
+ self.make(component, srcdir, builddir,
+ make_check_flags[comp_key][build],
+ make_check_env[comp_key][build])
+
+
+ def configure(self, component, srcdir, builddir, flags, env):
+ self.logger.debug("Configure " + str(flags) + " " + str(srcdir) + " -> "
+ + str(builddir))
+
+ configure_files = dict(
+ llvm=[(srcdir + "/configure", builddir + "/Makefile")],
+ llvm_gcc=[(srcdir + "/configure", builddir + "/Makefile"),
+ (srcdir + "/gcc/configure", builddir + "/gcc/Makefile")],
+ llvm2=[(srcdir + "/configure", builddir + "/Makefile")],
+ gcc=[(srcdir + "/configure", builddir + "/Makefile"),
+ (srcdir + "/gcc/configure", builddir + "/gcc/Makefile")],
+ dragonegg=[()])
+
+
+ doconfig = False
+ for conf, mf in configure_files[component.replace("-", "_")]:
+ if not os.path.exists(conf):
+ return
+ if os.path.exists(conf) and os.path.exists(mf):
+ confstat = os.stat(conf)
+ makestat = os.stat(mf)
+ if confstat.st_mtime > makestat.st_mtime:
+ doconfig = True
+ break
+ else:
+ doconfig = True
+ break
+
+ if not doconfig and not self.options.force_configure:
+ return
+
+ program = srcdir + "/configure"
+ if not is_executable(program):
+ return
+
+ args = [program]
+ args += ["--verbose"]
+ args += flags
+ self.execute(args, builddir, env, component)
+
+ def make(self, component, srcdir, builddir, flags, env):
+ program = find_executable("make")
+ if program is None:
+ raise ExecutableNotFound
+
+ if not is_executable(program):
+ raise FileNotExecutable
+
+ args = [program]
+ args += flags
+ self.execute(args, builddir, env, component)
+
+# Global constants
+build_abbrev = dict(debug="dbg", release="opt", paranoid="par")
+
+# Parse options
+parser = optparse.OptionParser(version="%prog 1.0")
+add_options(parser)
+(options, args) = parser.parse_args()
+check_options(parser, options, build_abbrev.keys());
+
+if options.verbose:
+ logging.basicConfig(level=logging.DEBUG,
+ format='%(name)-13s: %(message)s')
+else:
+ logging.basicConfig(level=logging.INFO,
+ format='%(name)-13s: %(message)s')
+
+source_abbrev = get_path_abbrevs(set(options.src))
+branch_abbrev = get_path_abbrevs(set(options.branch))
+
+work_queue = queue.Queue()
+
+jobs = options.jobs // options.threads
+if jobs == 0:
+ jobs = 1
+
+numthreads = options.threads
+if jobs < numthreads:
+ numthreads = jobs
+ jobs = 1
+
+for t in range(numthreads):
+ builder = Builder(work_queue, jobs,
+ build_abbrev, source_abbrev, branch_abbrev,
+ options)
+ builder.daemon = True
+ builder.start()
+
+for build in set(options.build):
+ for source in set(options.src):
+ if options.branch is not None:
+ for branch in set(options.branch):
+ work_queue.put((source, branch, build))
+ else:
+ work_queue.put((source, None, build))
+
+work_queue.join()
diff --git a/utils/not/CMakeLists.txt b/utils/not/CMakeLists.txt
index 522708d..f4c0229 100644
--- a/utils/not/CMakeLists.txt
+++ b/utils/not/CMakeLists.txt
@@ -1,8 +1,8 @@
-add_executable(not
+add_llvm_utility(not
not.cpp
)
-target_link_libraries(not LLVMSupport 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 fef4802..f37f166 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 908abe9..9a924b5 100644
--- a/utils/not/not.cpp
+++ b/utils/not/not.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#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;
diff --git a/utils/unittest/UnitTestMain/Makefile b/utils/unittest/UnitTestMain/Makefile
index cec654f..3082779 100644
--- a/utils/unittest/UnitTestMain/Makefile
+++ b/utils/unittest/UnitTestMain/Makefile
@@ -27,4 +27,6 @@ ifneq ($(HAVE_PTHREAD), 1)
CPP.Flags += -DGTEST_HAS_PTHREAD=0
endif
+NO_INSTALL = 1
+
include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp
index 805dbd8..b35bae5 100644
--- a/utils/unittest/UnitTestMain/TestMain.cpp
+++ b/utils/unittest/UnitTestMain/TestMain.cpp
@@ -8,12 +8,12 @@
//===----------------------------------------------------------------------===//
#include "llvm/Config/config.h"
-#include "llvm/System/Signals.h"
+#include "llvm/Support/Signals.h"
#include "gtest/gtest.h"
#if defined(LLVM_ON_WIN32)
-# include <Windows.h>
+# include <windows.h>
# if defined(_MSC_VER)
# include <crtdbg.h>
# endif
diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h
index 921fad1..5470082 100644
--- a/utils/unittest/googletest/include/gtest/gtest.h
+++ b/utils/unittest/googletest/include/gtest/gtest.h
@@ -1258,6 +1258,8 @@ AssertionResult CmpHelperEQ(const char* expected_expression,
#pragma warning(push) // Saves the current warning state.
#pragma warning(disable:4389) // Temporarily disables warning on
// signed/unsigned mismatch.
+#pragma warning(disable:4805) // Temporarily disables warning on
+ // unsafe mix of types
#endif
if (expected == actual) {
diff --git a/utils/valgrind/i386-pc-linux-gnu.supp b/utils/valgrind/i386-pc-linux-gnu.supp
index c9f68a0..0509791 100644
--- a/utils/valgrind/i386-pc-linux-gnu.supp
+++ b/utils/valgrind/i386-pc-linux-gnu.supp
@@ -12,19 +12,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:Value4
- 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*
}
{
@@ -37,5 +37,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/valgrind/x86_64-pc-linux-gnu.supp b/utils/valgrind/x86_64-pc-linux-gnu.supp
index f5aae99..7b2dd45 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*
}