diff options
author | Jush Lu <jush.msn@gmail.com> | 2011-03-09 19:39:16 +0800 |
---|---|---|
committer | Jush Lu <jush.msn@gmail.com> | 2011-03-09 19:39:16 +0800 |
commit | b5530586d68bd25831a6796b5d3199cb0769a35c (patch) | |
tree | fac4a03b53b6a64b0c00f433e4d8b3c9f2bc67cd /utils | |
parent | b4e17c5bf4361bbdeced39aa071150d7fa9c3c10 (diff) | |
parent | d01f50f42ce60207ed6d27fb1778e456d83be06c (diff) | |
download | external_llvm-b5530586d68bd25831a6796b5d3199cb0769a35c.zip external_llvm-b5530586d68bd25831a6796b5d3199cb0769a35c.tar.gz external_llvm-b5530586d68bd25831a6796b5d3199cb0769a35c.tar.bz2 |
Merge upstream r127116
Diffstat (limited to 'utils')
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* } |