+++ /dev/null
-diff --git a/tools/spirv/CMakeLists.txt b/tools/spirv/CMakeLists.txt
-index af51f86..5775510 100644
---- a/tools/spirv/CMakeLists.txt
-+++ b/tools/spirv/CMakeLists.txt
-@@ -12,6 +12,7 @@ include_directories(../..)
-
- set(SOURCES
- main.cpp
-+ assembler_table.cpp
- disassemble.cpp
- header.cpp
- doc.cpp
-diff --git a/tools/spirv/OclDoc.cpp b/tools/spirv/OclDoc.cpp
-index 1f25221..ff2c7c6 100644
---- a/tools/spirv/OclDoc.cpp
-+++ b/tools/spirv/OclDoc.cpp
-@@ -28,11 +28,14 @@
- #include "headers/spirv.hpp"
- #include "headers/OpenCL.std.h"
-
--#include "doc.h"
- #include "OclDoc.h"
-
-+#include "assembler_table.h"
-+#include "doc.h"
-+
- #include <stdio.h>
- #include <string.h>
-+#include <cassert>
- #include <algorithm>
- #include <map>
-
-@@ -2187,4 +2190,31 @@ void PrintOclCommonDoc()
- PrintOclDoc(SPIROpenCLCommonVersion);
- }
-
-+void PrintOclInstructionsTable(std::ostream& out) {
-+ ParameterizeBuiltins(SPIROpenCLCommonVersion);
-+
-+ out << R"(
-+// OpenCL extended instructions table, one instruction per line.
-+// All instructions have a result type and a result ID.
-+// Fields in this file are:
-+// - name
-+// - extended instruction index
-+// - EmptyList, or List of operand classes.
-+)";
-+ for (int i = 0; i < OclExtInstCeiling; ++i) {
-+ const BuiltInFunctionParameters& inst = BuiltInDesc[i];
-+ // Skip gaps in the enum space, if any.
-+ if (0 == strcmp("unknown", inst.opName)) continue;
-+ assert(inst.hasType());
-+ assert(inst.hasResult());
-+ out << "ExtInst(" << inst.opName << ", " << i << ", ";
-+ std::vector<OperandClassInfo> classes_info;
-+ for (const auto& operand_class : inst.operands.classes()) {
-+ classes_info.push_back({operand_class, false /* not optional */});
-+ }
-+ PrintOperandClasses(classes_info, out);
-+ out << ")" << std::endl;
-+ }
-+}
-+
- }; // end namespace spv
-diff --git a/tools/spirv/OclDoc.h b/tools/spirv/OclDoc.h
-index 8568880..7cf8a31 100644
---- a/tools/spirv/OclDoc.h
-+++ b/tools/spirv/OclDoc.h
-@@ -35,6 +35,8 @@
- #include <map>
- #include "headers/spirv.hpp"
-
-+#include "doc.h"
-+
- namespace spv {
-
- void OclGetDebugNames(const char** names);
-@@ -189,6 +191,8 @@ public:
- int getImageType(int op) { return Type[op]; }
- AccessQualifier getAccessQualifier(int op) { return accessQualifier[op]; }
-
-+ const std::vector<OperandClass>& classes() const { return opClass; }
-+
- protected:
- std::vector<OperandClass> opClass;
- std::vector<const char*> desc;
-@@ -307,4 +311,7 @@ protected:
- // Print out the OpenCL common (all spec revisions) documentation.
- void PrintOclCommonDoc();
-
-+// Prints the OpenCL instructions table, for consumption by SPIR-V Tools.
-+void PrintOclInstructionsTable(std::ostream& out);
-+
- }; // end namespace spv
-diff --git a/tools/spirv/assembler_table.cpp b/tools/spirv/assembler_table.cpp
-new file mode 100644
-index 0000000..8dd8fa1
---- /dev/null
-+++ b/tools/spirv/assembler_table.cpp
-@@ -0,0 +1,229 @@
-+// Copyright (c) 2015-2016 The Khronos Group Inc.
-+//
-+// Permission is hereby granted, free of charge, to any person obtaining a
-+// copy of this software and/or associated documentation files (the
-+// "Materials"), to deal in the Materials without restriction, including
-+// without limitation the rights to use, copy, modify, merge, publish,
-+// distribute, sublicense, and/or sell copies of the Materials, and to
-+// permit persons to whom the Materials are furnished to do so, subject to
-+// the following conditions:
-+//
-+// The above copyright notice and this permission notice shall be included
-+// in all copies or substantial portions of the Materials.
-+//
-+// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
-+// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
-+// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
-+// https://www.khronos.org/registry/
-+//
-+// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-+
-+#include "assembler_table.h"
-+
-+#include <cassert>
-+#include <cstring>
-+#include <sstream>
-+
-+#include "doc.h"
-+
-+namespace spv {
-+
-+namespace {
-+
-+// Returns true if the given instruction can vary in width.
-+bool IsVariableLength(const InstructionParameters& inst) {
-+ const OperandParameters& operands = inst.operands;
-+ for (int i = 0; i < operands.getNum() ; i++) {
-+ switch (operands.getClass(i)) {
-+ case spv::OperandVariableIds:
-+ case spv::OperandOptionalLiteral:
-+ case spv::OperandOptionalLiteralString:
-+ case spv::OperandVariableLiterals:
-+ case spv::OperandVariableIdLiteral:
-+ case spv::OperandVariableLiteralId:
-+ case spv::OperandLiteralString:
-+ return true;
-+ default:
-+ break;
-+ }
-+ if (operands.isOptional(i)) return true;
-+ }
-+ return false;
-+}
-+
-+// Returns a string for the given operand class, or nullptr if it's invalid.
-+const char* GetOperandClassString(OperandClass operandClass) {
-+ switch (operandClass) {
-+#define CASE(X) case X: return #X;
-+ CASE(OperandNone)
-+ CASE(OperandId)
-+ CASE(OperandVariableIds)
-+ CASE(OperandOptionalLiteral)
-+ CASE(OperandOptionalLiteralString)
-+ CASE(OperandVariableLiterals)
-+ CASE(OperandVariableIdLiteral)
-+ CASE(OperandVariableLiteralId)
-+ CASE(OperandLiteralNumber)
-+ CASE(OperandLiteralString)
-+ CASE(OperandSource)
-+ CASE(OperandExecutionModel)
-+ CASE(OperandAddressing)
-+ CASE(OperandMemory)
-+ CASE(OperandExecutionMode)
-+ CASE(OperandStorage)
-+ CASE(OperandDimensionality)
-+ CASE(OperandSamplerAddressingMode)
-+ CASE(OperandSamplerFilterMode)
-+ CASE(OperandSamplerImageFormat)
-+ CASE(OperandImageChannelOrder)
-+ CASE(OperandImageChannelDataType)
-+ CASE(OperandImageOperands)
-+ CASE(OperandFPFastMath)
-+ CASE(OperandFPRoundingMode)
-+ CASE(OperandLinkageType)
-+ CASE(OperandAccessQualifier)
-+ CASE(OperandFuncParamAttr)
-+ CASE(OperandDecoration)
-+ CASE(OperandBuiltIn)
-+ CASE(OperandSelect)
-+ CASE(OperandLoop)
-+ CASE(OperandFunction)
-+ CASE(OperandMemorySemantics)
-+ CASE(OperandMemoryAccess)
-+ CASE(OperandScope)
-+ CASE(OperandGroupOperation)
-+ CASE(OperandKernelEnqueueFlags)
-+ CASE(OperandKernelProfilingInfo)
-+ CASE(OperandCapability)
-+ CASE(OperandOpcode)
-+#undef CASE
-+
-+ case OperandCount:
-+ default:
-+ break;
-+ }
-+ return nullptr;
-+}
-+} // anonymous namespace
-+
-+// Prints a listing of the operand kinds for the given instruction.
-+// If the list is empty, then emit just "EmptyList",
-+// otherwise the output looks like a call to the "List" macro.
-+void PrintOperandClasses(const std::vector<OperandClassInfo>& classes, std::ostream& out) {
-+ std::stringstream contents;
-+ int numPrinted = 0;
-+ for (auto class_info : classes) {
-+ if (const char* name = GetOperandClassString(class_info.value)) {
-+ if (numPrinted) contents << ", ";
-+ switch (class_info.value) {
-+ case OperandId:
-+ case OperandImageOperands:
-+ case OperandLiteralString:
-+ case OperandMemoryAccess:
-+ case OperandAccessQualifier:
-+ if (class_info.is_optional) {
-+ contents << "OperandOptional" << (name + strlen("Operand"));
-+ } else {
-+ contents << name;
-+ }
-+ break;
-+ default:
-+ contents << name;
-+ break;
-+ }
-+ numPrinted++;
-+ if (class_info.value == OperandImageOperands) {
-+ // There are Id and/or VariableIds after this. Skip them
-+ // because the bits in an OperandImageOperands determine
-+ // exactly the number of Ids required to follow.
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (numPrinted)
-+ out << "List(" << contents.str() << ")";
-+ else
-+ out << "EmptyList";
-+}
-+} // namespace spv
-+
-+namespace spv {
-+
-+// Prints a listing of the operand kinds for the given instruction.
-+// If the list is empty, then emit just "EmptyList",
-+// otherwise the output looks like a call to the "List" macro.
-+void PrintOperandClassesForInstruction(const InstructionParameters& inst,
-+ std::ostream& out) {
-+ std::vector<OperandClassInfo> result;
-+
-+ const OperandParameters& operands = inst.operands;
-+ for (int i = 0; i < operands.getNum(); i++) {
-+ result.push_back({operands.getClass(i), operands.isOptional(i)});
-+ }
-+ PrintOperandClasses(result, out);
-+}
-+
-+// Prints the table entry for the given instruction with the given opcode.
-+void PrintInstructionDesc(int opcode, const InstructionParameters& inst, std::ostream& out) {
-+ const char* name = OpcodeString(opcode);
-+ // There can be gaps in the listing.
-+ // All valid operations have a name beginning with "Op".
-+ if (strlen(name) > 2 && name[0] == 'O' && name[1] == 'p') {
-+ out << "Instruction("
-+ << name + 2 << ", "; // Skip the "Op" part.
-+ out << (inst.hasResult() ? 1 : 0) << ", ";
-+ out << (inst.hasType() ? 1 : 0) << ", ";
-+ out << inst.operands.getNum() << ", ";
-+
-+ // Emit the capability, if any.
-+ // The SPIR-V tools doesn't handle the concept of depending on more than
-+ // one capability. So call it out separately. Currently the biggest case
-+ // is 2. This is a big hack.
-+ out << inst.capabilities.size() << ", ";
-+ assert(inst.capabilities.size() < 3);
-+ if (inst.capabilities.size() == 1) {
-+ out << "Capability(" << CapabilityString(inst.capabilities[0]) << "), ";
-+ } else if (inst.capabilities.size() == 2) {
-+ out << "Capability2(" << CapabilityString(inst.capabilities[0]) << ","
-+ << CapabilityString(inst.capabilities[1]) << "), ";
-+ } else {
-+ out << "Capability(None), ";
-+ }
-+
-+ out << (IsVariableLength(inst) ? 1 : 0) << ", ";
-+ PrintOperandClassesForInstruction(inst, out);
-+ out << ")" << std::endl;
-+ }
-+}
-+
-+void PrintAssemblerTable(std::ostream& out) {
-+ out << "// Instruction fields are:\n"
-+ << "// name - skips the \"Op\" prefix\n"
-+ << "// {0|1} - whether the instruction generates a result Id\n"
-+ << "// {0|1} - whether the instruction encodes the type of the result Id\n"
-+ << "// numLogicalOperands - does not include result id or type id\n"
-+ << "// numCapabilities - we only handle 0 or 1 required capabilities\n"
-+ << "// Capability(<capability-name>) - capability required to use this instruction. Might be None.\n"
-+ << "// There can be Capability2(a,b) for dependence on two capabilities.\n"
-+ << "// {0|1} - whether the instruction is variable number of logical operands\n"
-+ << "// EmptyList or List(...) - list of classes of logical operands\n"
-+ << "// Example use:\n"
-+ << "// #define EmptyList {}\n"
-+ << "// #define List(...) {__VA_ARGS__}\n"
-+ << "// #define Capability(C) Capability##C\n"
-+ << "// #define CapabilityNone -1\n"
-+ << "// #define Instruction(Name,HasResult,HasType,NumLogicalOperands,CapabiltyRequired,IsVariable,LogicalArgsList)\n";
-+
-+ for (int i = 0; i < spv::OpcodeCeiling ; i++ ) {
-+ PrintInstructionDesc(i, InstructionDesc[i], out);
-+ }
-+}
-+
-+}
-diff --git a/tools/spirv/assembler_table.h b/tools/spirv/assembler_table.h
-new file mode 100644
-index 0000000..16ea384
---- /dev/null
-+++ b/tools/spirv/assembler_table.h
-@@ -0,0 +1,55 @@
-+// Copyright (c) 2015-2016 The Khronos Group Inc.
-+//
-+// Permission is hereby granted, free of charge, to any person obtaining a
-+// copy of this software and/or associated documentation files (the
-+// "Materials"), to deal in the Materials without restriction, including
-+// without limitation the rights to use, copy, modify, merge, publish,
-+// distribute, sublicense, and/or sell copies of the Materials, and to
-+// permit persons to whom the Materials are furnished to do so, subject to
-+// the following conditions:
-+//
-+// The above copyright notice and this permission notice shall be included
-+// in all copies or substantial portions of the Materials.
-+//
-+// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
-+// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
-+// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
-+// https://www.khronos.org/registry/
-+//
-+// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-+
-+#pragma once
-+#ifndef ASSEMBLER_TABLE_H
-+#define ASSEMBLER_TABLE_H
-+
-+#include <iostream>
-+#include <vector>
-+
-+#include "doc.h"
-+
-+namespace spv {
-+
-+ // Relevant facts about an operand class value.
-+ struct OperandClassInfo {
-+ OperandClass value;
-+ bool is_optional;
-+ };
-+
-+ // Prints the tables used to define the structure of instructions.
-+ // Assumes that parameterization has already occurred
-+ void PrintAssemblerTable(std::ostream& out);
-+
-+ // Prints a listing of the operand kinds.
-+ // If the list is empty, then emit just "EmptyList",
-+ // otherwise the output looks like a call to the "List" macro.
-+ void PrintOperandClasses(const std::vector<OperandClassInfo>& classes, std::ostream& out);
-+
-+}; // end namespace spv
-+
-+#endif // ASSEMBLER_TABLE_H
-diff --git a/tools/spirv/doc.h b/tools/spirv/doc.h
-index 4c11d3b..6e1718a 100644
---- a/tools/spirv/doc.h
-+++ b/tools/spirv/doc.h
-@@ -32,6 +32,9 @@
- //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- //POSSIBILITY OF SUCH DAMAGE.
-
-+#ifndef DOC_H_
-+#define DOC_H_
-+
- //
- // Author: John Kessenich, LunarG
- //
-@@ -81,6 +84,7 @@ const char* KernelEnqueueFlagsString(int);
- const char* KernelProfilingInfoString(int);
- const char* CapabilityString(int);
- const char* OpcodeString(int);
-+const char* OperandClassString(int);
-
- // For grouping opcodes into subsections
- enum OpcodeClass {
-@@ -157,6 +161,10 @@ enum OperandClass {
-
- OperandOpcode,
-
-+ // The operand class enum is not part of the spec, so
-+ // it should come after OperandOpcode.
-+ OperandOperandClass,
-+
- OperandCount
- };
-
-@@ -259,3 +267,5 @@ const char* AccessQualifierString(int attr);
- void PrintOperands(const OperandParameters& operands, int reservedOperands);
-
- }; // end namespace spv
-+
-+#endif // DOC_H_
-diff --git a/tools/spirv/main.cpp b/tools/spirv/main.cpp
-index d7312f9..e1413bb 100644
---- a/tools/spirv/main.cpp
-+++ b/tools/spirv/main.cpp
-@@ -46,6 +46,7 @@ namespace spv {
- #include "headers/OpenCL.std.h"
-
- // This tool's includes
-+#include "assembler_table.h"
- #include "disassemble.h"
- #include "header.h"
- #include "doc.h"
-@@ -65,6 +66,8 @@ enum TOptions {
- EOptionDisassemble = 0x004,
- EOptionPrintHeader = 0x008,
- EOptionPrintOclBuiltinsAsciidoc = 0x010,
-+ EOptionPrintAssemblerTable = 0x020,
-+ EOptionPrintOclInstructionsTable = 0x040,
- };
-
- std::string Filename;
-@@ -86,9 +89,11 @@ void Usage()
- " -H print header in all supported languages to files in current directory\n"
- " -p print documentation\n"
- " -s [version] prints the SPIR-V extended instructions documentation\n"
-- " 'CL12': OpenCL 1.2 extended instructions documentation\n"
-- " 'CL20': OpenCL 2.0 extended instructions documentation\n"
-- " 'CL21': OpenCL 2.1 extended instructions documentation\n"
-+ " 'OpenCL': OpenCL 1.2, 2.0, 2.1 extended instructions documentation\n"
-+ " 'GLSL': GLSL extended instructions documentation\n"
-+ " -a print table for the assembler\n"
-+ " -C print OpenCL instructions for the assembler\n"
-+ " This is incompatibile with -s OpenCL\n"
- );
- }
-
-@@ -155,6 +160,12 @@ bool ProcessArguments(int argc, char* argv[])
- }
- return true;
- }
-+ case 'a':
-+ Options |= EOptionPrintAssemblerTable;
-+ break;
-+ case 'C':
-+ Options |= EOptionPrintOclInstructionsTable;
-+ break;
- default:
- return false;
- }
-@@ -162,6 +173,9 @@ bool ProcessArguments(int argc, char* argv[])
- Filename = std::string(argv[0]);
- }
- }
-+ if ((Options & EOptionPrintOclBuiltinsAsciidoc) &&
-+ (Options & EOptionPrintOclInstructionsTable))
-+ return false;
-
- return true;
- }
-@@ -220,5 +234,11 @@ int main(int argc, char* argv[])
- if (Options & EOptionPrintHeader)
- spv::PrintHeader(Language, std::cout);
-
-+ if (Options & EOptionPrintAssemblerTable)
-+ spv::PrintAssemblerTable(std::cout);
-+
-+ if (Options & EOptionPrintOclInstructionsTable)
-+ spv::PrintOclInstructionsTable(std::cout);
-+
- return 0;
- }