Add OpenCL extended instructions.

Versions 1.2, 2.0, and 2.1 all use the same
extended instruction list.

Updated the source code patch for the SPIR-V doc generator,
so it can both generate the core syntax table, and also the
OpenCL extended instructions table.

Tested the Math and Common functions.
TODO: test the remaining entries.
This commit is contained in:
David Neto 2015-10-14 17:02:11 -04:00
parent ccc210b4cc
commit 21c4ad4b22
6 changed files with 628 additions and 65 deletions

View File

@ -182,6 +182,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
${CMAKE_CURRENT_SOURCE_DIR}/test/Comment.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/DiagnosticPrint.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/DiagnosticStream.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ExtInst.OpenCL.std.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ExtInstGLSLstd450.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/FixWord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ImmediateInt.cpp

View File

@ -246,9 +246,7 @@ typedef enum spv_operand_type_t {
typedef enum spv_ext_inst_type_t {
SPV_EXT_INST_TYPE_NONE,
SPV_EXT_INST_TYPE_GLSL_STD_450,
SPV_EXT_INST_TYPE_OPENCL_STD_12,
SPV_EXT_INST_TYPE_OPENCL_STD_20,
SPV_EXT_INST_TYPE_OPENCL_STD_21,
SPV_EXT_INST_TYPE_OPENCL_STD,
SPV_FORCE_32_BIT_ENUM(spv_ext_inst_type_t)
} spv_ext_inst_type_t;

View File

@ -96,19 +96,24 @@ static const spv_ext_inst_desc_t glslStd450Entries[] = {
{GLSL450Inst2(InterpolateAtOffset)},
};
static const spv_ext_inst_desc_t openclStd12Entries[] = {
{"placeholder", 0, {}},
// TODO: Add remaining OpenCL.std.12 instructions
};
static const spv_ext_inst_desc_t openclStd20Entries[] = {
{"placeholder", 0, {}},
// TODO: Add remaining OpenCL.std.20 instructions
};
static const spv_ext_inst_desc_t openclStd21Entries[] = {
{"placeholder", 0, {}},
// TODO: Add remaining OpenCL.std.21 instructions
static const spv_ext_inst_desc_t openclEntries[] = {
#define ExtInst(Name, Opcode, OperandList) {#Name, Opcode, OperandList},
#define EmptyList \
{}
#define List(...) \
{ __VA_ARGS__ }
#define OperandId SPV_OPERAND_TYPE_ID
#define OperandLiteralNumber SPV_OPERAND_TYPE_LITERAL_NUMBER
#define OperandFPRoundingMode SPV_OPERAND_TYPE_FP_ROUNDING_MODE
#define OperandVariableIds SPV_OPERAND_TYPE_VARIABLE_ID
#include "opencl_std_ext_inst.inc"
#undef ExtList
#undef EmptyList
#undef List
#undef OperandId
#undef OperandLiteralNumber
#undef OperandFPRoundingMode
#undef OperandVariableIds
};
spv_result_t spvExtInstTableGet(spv_ext_inst_table *pExtInstTable) {
@ -118,15 +123,9 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table *pExtInstTable) {
{SPV_EXT_INST_TYPE_GLSL_STD_450,
sizeof(glslStd450Entries) / sizeof(spv_ext_inst_desc_t),
glslStd450Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD_12,
sizeof(openclStd12Entries) / sizeof(spv_ext_inst_desc_t),
openclStd12Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD_20,
sizeof(openclStd20Entries) / sizeof(spv_ext_inst_desc_t),
openclStd20Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD_21,
sizeof(openclStd21Entries) / sizeof(spv_ext_inst_desc_t),
openclStd21Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD,
sizeof(openclEntries) / sizeof(spv_ext_inst_desc_t),
openclEntries},
};
static const spv_ext_inst_table_t table = {
@ -138,17 +137,13 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table *pExtInstTable) {
}
spv_ext_inst_type_t spvExtInstImportTypeGet(const char *name) {
// The names are specified by the respective extension instruction
// specifications.
if (!strcmp("GLSL.std.450", name)) {
return SPV_EXT_INST_TYPE_GLSL_STD_450;
}
if (!strcmp("OpenCL.std.12", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD_12;
}
if (!strcmp("OpenCL.std.20", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD_20;
}
if (!strcmp("OpenCL.std.21", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD_21;
if (!strcmp("OpenCL.std", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD;
}
return SPV_EXT_INST_TYPE_NONE;
}

View File

@ -0,0 +1,212 @@
// 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.
ExtInst(acos, 0, List(OperandId))
ExtInst(acosh, 1, List(OperandId))
ExtInst(acospi, 2, List(OperandId))
ExtInst(asin, 3, List(OperandId))
ExtInst(asinh, 4, List(OperandId))
ExtInst(asinpi, 5, List(OperandId))
ExtInst(atan, 6, List(OperandId))
ExtInst(atan2, 7, List(OperandId, OperandId))
ExtInst(atanh, 8, List(OperandId))
ExtInst(atanpi, 9, List(OperandId))
ExtInst(atan2pi, 10, List(OperandId, OperandId))
ExtInst(cbrt, 11, List(OperandId))
ExtInst(ceil, 12, List(OperandId))
ExtInst(copysign, 13, List(OperandId, OperandId))
ExtInst(cos, 14, List(OperandId))
ExtInst(cosh, 15, List(OperandId))
ExtInst(cospi, 16, List(OperandId))
ExtInst(erfc, 17, List(OperandId))
ExtInst(erf, 18, List(OperandId))
ExtInst(exp, 19, List(OperandId))
ExtInst(exp2, 20, List(OperandId))
ExtInst(exp10, 21, List(OperandId))
ExtInst(expm1, 22, List(OperandId))
ExtInst(fabs, 23, List(OperandId))
ExtInst(fdim, 24, List(OperandId, OperandId))
ExtInst(floor, 25, List(OperandId))
ExtInst(fma, 26, List(OperandId, OperandId, OperandId))
ExtInst(fmax, 27, List(OperandId, OperandId))
ExtInst(fmin, 28, List(OperandId, OperandId))
ExtInst(fmod, 29, List(OperandId, OperandId))
ExtInst(fract, 30, List(OperandId, OperandId))
ExtInst(frexp, 31, List(OperandId, OperandId))
ExtInst(hypot, 32, List(OperandId, OperandId))
ExtInst(ilogb, 33, List(OperandId))
ExtInst(ldexp, 34, List(OperandId, OperandId))
ExtInst(lgamma, 35, List(OperandId))
ExtInst(lgamma_r, 36, List(OperandId, OperandId))
ExtInst(log, 37, List(OperandId))
ExtInst(log2, 38, List(OperandId))
ExtInst(log10, 39, List(OperandId))
ExtInst(log1p, 40, List(OperandId))
ExtInst(logb, 41, List(OperandId))
ExtInst(mad, 42, List(OperandId, OperandId, OperandId))
ExtInst(maxmag, 43, List(OperandId, OperandId))
ExtInst(minmag, 44, List(OperandId, OperandId))
ExtInst(modf, 45, List(OperandId, OperandId))
ExtInst(nan, 46, List(OperandId))
ExtInst(nextafter, 47, List(OperandId, OperandId))
ExtInst(pow, 48, List(OperandId, OperandId, OperandId))
ExtInst(pown, 49, List(OperandId))
ExtInst(powr, 50, List(OperandId, OperandId))
ExtInst(remainder, 51, List(OperandId, OperandId))
ExtInst(remquo, 52, List(OperandId, OperandId, OperandId))
ExtInst(rint, 53, List(OperandId))
ExtInst(rootn, 54, List(OperandId, OperandId))
ExtInst(round, 55, List(OperandId))
ExtInst(rsqrt, 56, List(OperandId))
ExtInst(sin, 57, List(OperandId))
ExtInst(sincos, 58, List(OperandId, OperandId))
ExtInst(sinh, 59, List(OperandId))
ExtInst(sinpi, 60, List(OperandId))
ExtInst(sqrt, 61, List(OperandId))
ExtInst(tan, 62, List(OperandId))
ExtInst(tanh, 63, List(OperandId))
ExtInst(tanpi, 64, List(OperandId))
ExtInst(tgamma, 65, List(OperandId))
ExtInst(trunc, 66, List(OperandId))
ExtInst(half_cos, 67, List(OperandId))
ExtInst(half_divide, 68, List(OperandId, OperandId))
ExtInst(half_exp, 69, List(OperandId))
ExtInst(half_exp2, 70, List(OperandId))
ExtInst(half_exp10, 71, List(OperandId))
ExtInst(half_log, 72, List(OperandId))
ExtInst(half_log2, 73, List(OperandId))
ExtInst(half_log10, 74, List(OperandId))
ExtInst(half_powr, 75, List(OperandId, OperandId))
ExtInst(half_recip, 76, List(OperandId))
ExtInst(half_rsqrt, 77, List(OperandId))
ExtInst(half_sin, 78, List(OperandId))
ExtInst(half_sqrt, 79, List(OperandId))
ExtInst(half_tan, 80, List(OperandId))
ExtInst(native_cos, 81, List(OperandId))
ExtInst(native_divide, 82, List(OperandId, OperandId))
ExtInst(native_exp, 83, List(OperandId))
ExtInst(native_exp2, 84, List(OperandId))
ExtInst(native_exp10, 85, List(OperandId))
ExtInst(native_log, 86, List(OperandId))
ExtInst(native_log2, 87, List(OperandId))
ExtInst(native_log10, 88, List(OperandId))
ExtInst(native_powr, 89, List(OperandId, OperandId))
ExtInst(native_recip, 90, List(OperandId))
ExtInst(native_rsqrt, 91, List(OperandId))
ExtInst(native_sin, 92, List(OperandId))
ExtInst(native_sqrt, 93, List(OperandId))
ExtInst(native_tan, 94, List(OperandId))
ExtInst(fclamp, 95, List(OperandId, OperandId, OperandId))
ExtInst(degrees, 96, List(OperandId))
ExtInst(fmax_common, 97, List(OperandId, OperandId))
ExtInst(fmin_common, 98, List(OperandId, OperandId))
ExtInst(mix, 99, List(OperandId, OperandId, OperandId))
ExtInst(radians, 100, List(OperandId))
ExtInst(step, 101, List(OperandId, OperandId))
ExtInst(smoothstep, 102, List(OperandId, OperandId, OperandId))
ExtInst(sign, 103, List(OperandId))
ExtInst(cross, 104, List(OperandId, OperandId))
ExtInst(distance, 105, List(OperandId, OperandId))
ExtInst(length, 106, List(OperandId))
ExtInst(normalize, 107, List(OperandId))
ExtInst(fast_distance, 108, List(OperandId, OperandId))
ExtInst(fast_length, 109, List(OperandId))
ExtInst(fast_normalize, 110, List(OperandId))
ExtInst(read_imagef, 111, EmptyList)
ExtInst(read_imagei, 112, EmptyList)
ExtInst(read_imageui, 113, EmptyList)
ExtInst(read_imageh, 114, EmptyList)
ExtInst(read_imagef_samplerless, 115, EmptyList)
ExtInst(read_imagei_samplerless, 116, EmptyList)
ExtInst(read_imageui_samplerless, 117, EmptyList)
ExtInst(read_imageh_samplerless, 118, EmptyList)
ExtInst(write_imagef, 119, EmptyList)
ExtInst(write_imagei, 120, EmptyList)
ExtInst(write_imageui, 121, EmptyList)
ExtInst(write_imageh, 122, EmptyList)
ExtInst(read_imagef_mipmap_lod, 123, EmptyList)
ExtInst(read_imagei_mipmap_lod, 124, EmptyList)
ExtInst(read_imageui_mipmap_lod, 125, EmptyList)
ExtInst(read_imagef_mipmap_gradient, 126, EmptyList)
ExtInst(read_imagei_mipmap_gradient, 127, EmptyList)
ExtInst(read_imageui_mipmap_gradient, 128, EmptyList)
ExtInst(write_imagef_mipmap_lod, 129, List(OperandId, OperandId, OperandId, OperandId))
ExtInst(write_imagei_mipmap_lod, 130, List(OperandId, OperandId, OperandId, OperandId))
ExtInst(write_imageui_mipmap_lod, 131, List(OperandId, OperandId, OperandId, OperandId))
ExtInst(get_image_width, 132, EmptyList)
ExtInst(get_image_height, 133, EmptyList)
ExtInst(get_image_depth, 134, EmptyList)
ExtInst(get_image_channel_data_type, 135, EmptyList)
ExtInst(get_image_channel_order, 136, EmptyList)
ExtInst(get_image_dim, 137, EmptyList)
ExtInst(get_image_array_size, 138, EmptyList)
ExtInst(get_image_num_samples, 139, EmptyList)
ExtInst(get_image_num_mip_levels, 140, EmptyList)
ExtInst(s_abs, 141, List(OperandId))
ExtInst(s_abs_diff, 142, List(OperandId, OperandId))
ExtInst(s_add_sat, 143, List(OperandId, OperandId))
ExtInst(u_add_sat, 144, List(OperandId, OperandId))
ExtInst(s_hadd, 145, List(OperandId, OperandId))
ExtInst(u_hadd, 146, List(OperandId, OperandId))
ExtInst(s_rhadd, 147, List(OperandId, OperandId))
ExtInst(u_rhadd, 148, List(OperandId, OperandId))
ExtInst(s_clamp, 149, List(OperandId, OperandId, OperandId))
ExtInst(u_clamp, 150, List(OperandId, OperandId, OperandId))
ExtInst(clz, 151, List(OperandId))
ExtInst(ctz, 152, List(OperandId))
ExtInst(s_mad_hi, 153, List(OperandId, OperandId, OperandId))
ExtInst(u_mad_sat, 154, List(OperandId, OperandId, OperandId))
ExtInst(s_mad_sat, 155, List(OperandId, OperandId, OperandId))
ExtInst(s_max, 156, List(OperandId, OperandId))
ExtInst(u_max, 157, List(OperandId, OperandId))
ExtInst(s_min, 158, List(OperandId, OperandId))
ExtInst(u_min, 159, List(OperandId, OperandId))
ExtInst(s_mul_hi, 160, List(OperandId, OperandId))
ExtInst(rotate, 161, List(OperandId, OperandId))
ExtInst(s_sub_sat, 162, List(OperandId, OperandId))
ExtInst(u_sub_sat, 163, List(OperandId, OperandId))
ExtInst(u_upsample, 164, List(OperandId, OperandId))
ExtInst(s_upsample, 165, List(OperandId, OperandId))
ExtInst(popcount, 166, List(OperandId))
ExtInst(s_mad24, 167, List(OperandId, OperandId, OperandId))
ExtInst(u_mad24, 168, List(OperandId, OperandId, OperandId))
ExtInst(s_mul24, 169, List(OperandId, OperandId))
ExtInst(u_mul24, 170, List(OperandId, OperandId))
ExtInst(vloadn, 171, List(OperandId, OperandId, OperandLiteralNumber))
ExtInst(vstoren, 172, List(OperandId, OperandId, OperandId))
ExtInst(vload_half, 173, List(OperandId, OperandId))
ExtInst(vload_halfn, 174, List(OperandId, OperandId, OperandLiteralNumber))
ExtInst(vstore_half, 175, List(OperandId, OperandId, OperandId))
ExtInst(vstore_half_r, 176, List(OperandId, OperandId, OperandId, OperandFPRoundingMode))
ExtInst(vstore_halfn, 177, List(OperandId, OperandId, OperandId))
ExtInst(vstore_halfn_r, 178, List(OperandId, OperandId, OperandId, OperandFPRoundingMode))
ExtInst(vloada_halfn, 179, List(OperandId, OperandId, OperandLiteralNumber))
ExtInst(vstorea_halfn, 180, List(OperandId, OperandId, OperandId))
ExtInst(vstorea_halfn_r, 181, List(OperandId, OperandId, OperandId, OperandFPRoundingMode))
ExtInst(shuffle, 182, List(OperandId, OperandId))
ExtInst(shuffle2, 183, List(OperandId, OperandId, OperandId))
ExtInst(printf, 184, List(OperandId, OperandVariableIds))
ExtInst(prefetch, 185, List(OperandId, OperandId))
ExtInst(bitselect, 186, List(OperandId, OperandId, OperandId))
ExtInst(select, 187, List(OperandId, OperandId, OperandId))
ExtInst(read_pipe, 188, EmptyList)
ExtInst(write_pipe, 189, EmptyList)
ExtInst(reserve_read_pipe, 190, EmptyList)
ExtInst(reserve_write_pipe, 191, EmptyList)
ExtInst(commit_read_pipe, 192, EmptyList)
ExtInst(commit_write_pipe, 193, EmptyList)
ExtInst(is_valid_reserve_id, 194, EmptyList)
ExtInst(work_group_reserve_read_pipe, 195, EmptyList)
ExtInst(work_group_reserve_write_pipe, 196, EmptyList)
ExtInst(work_group_commit_read_pipe, 197, EmptyList)
ExtInst(work_group_commit_write_pipe, 198, EmptyList)
ExtInst(get_pipe_num_packets, 199, EmptyList)
ExtInst(get_pipe_max_packets, 200, EmptyList)
ExtInst(u_abs, 201, List(OperandId))
ExtInst(u_abs_diff, 202, List(OperandId, OperandId))
ExtInst(u_mul_hi, 203, List(OperandId, OperandId))
ExtInst(u_mad_hi, 204, List(OperandId, OperandId, OperandId))

View File

@ -10,12 +10,90 @@ index af51f86..5775510 100644
disassemble.cpp
header.cpp
doc.cpp
diff --git a/tools/spirv/OclDoc.cpp b/tools/spirv/OclDoc.cpp
index c94eae2..ea47d42 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>
@@ -2358,4 +2361,27 @@ 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 << ", ";
+ PrintOperandClasses(inst.operands.classes(), 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..5a68ade
index 0000000..85bca89
--- /dev/null
+++ b/tools/spirv/assembler_table.cpp
@@ -0,0 +1,200 @@
@@ -0,0 +1,214 @@
+// Copyright (c) 2015 The Khronos Group Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
@ -55,7 +133,7 @@ index 0000000..5a68ade
+namespace {
+
+// Returns true if the given instruction can vary in width.
+bool isVariableLength(const InstructionParameters& inst) {
+bool IsVariableLength(const InstructionParameters& inst) {
+ const OperandParameters& operands = inst.operands;
+ for (int i = 0; i < operands.getNum() ; i++) {
+ switch (operands.getClass(i)) {
@ -76,9 +154,8 @@ index 0000000..5a68ade
+ return false;
+}
+
+// Returns a string for the given operand class, or nullptr if
+// it's invalid.
+const char* getOperandClassString(OperandClass operandClass) {
+// 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)
@ -126,26 +203,23 @@ index 0000000..5a68ade
+ CASE(OperandOpcode)
+#undef CASE
+
+// case OperandNone:
+ 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 InstructionParameters& inst, std::ostream& out) {
+void PrintOperandClasses(const std::vector<OperandClass>& classes, std::ostream& out) {
+ std::stringstream contents;
+
+ const OperandParameters& operands = inst.operands;
+ int numPrinted = 0;
+ for (int i = 0; i < operands.getNum() ; i++) {
+ if (const char* name = getOperandClassString(operands.getClass(i))) {
+ if (numPrinted)
+ contents << ", ";
+ for (auto operandClass : classes) {
+ if (const char* name = GetOperandClassString(operandClass)) {
+ if (numPrinted) contents << ", ";
+ contents << name;
+ numPrinted++;
+ }
@ -156,9 +230,27 @@ index 0000000..5a68ade
+ else
+ out << "EmptyList";
+}
+} // namespace spv
+
+namespace spv {
+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 PrintOperandClassesForInstruction(const InstructionParameters& inst,
+ std::ostream& out) {
+ std::vector<OperandClass> result;
+
+ const OperandParameters& operands = inst.operands;
+ for (int i = 0; i < operands.getNum(); i++) {
+ result.push_back(operands.getClass(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) {
+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".
@ -184,13 +276,13 @@ index 0000000..5a68ade
+ out << "Capability(None), ";
+ }
+
+ out << (isVariableLength(inst) ? 1 : 0) << ", ";
+ printOperandClasses(inst, out);
+ out << (IsVariableLength(inst) ? 1 : 0) << ", ";
+ PrintOperandClassesForInstruction(inst, out);
+ out << ")" << std::endl;
+ }
+}
+
+}
+} // anonymous namespace
+
+void PrintAssemblerTable(std::ostream& out) {
+ out << "// Instruction fields are:\n"
@ -211,17 +303,17 @@ index 0000000..5a68ade
+ << "// #define Instruction(Name,HasResult,HasType,NumLogicalOperands,CapabiltyRequired,IsVariable,LogicalArgsList)\n";
+
+ for (int i = 0; i < spv::OpcodeCeiling ; i++ ) {
+ printInstructionDesc(i, InstructionDesc[i], out);
+ 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..03ab769
index 0000000..b98303a
--- /dev/null
+++ b/tools/spirv/assembler_table.h
@@ -0,0 +1,41 @@
@@ -0,0 +1,49 @@
+// Copyright (c) 2015 The Khronos Group Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
@ -253,6 +345,9 @@ index 0000000..03ab769
+#define ASSEMBLER_TABLE_H
+
+#include <iostream>
+#include <vector>
+
+#include "doc.h"
+
+namespace spv {
+
@ -260,14 +355,29 @@ index 0000000..03ab769
+ // 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<OperandClass>& classes, std::ostream& out);
+
+}; // end namespace spv
+
+#endif // ASSEMBLER_TABLE_H
diff --git a/tools/spirv/doc.h b/tools/spirv/doc.h
index 78b1031..5984835 100644
index 78b1031..a182509 100644
--- a/tools/spirv/doc.h
+++ b/tools/spirv/doc.h
@@ -81,6 +81,7 @@ const char* KernelEnqueueFlagsString(int);
@@ -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);
@ -275,7 +385,7 @@ index 78b1031..5984835 100644
// For grouping opcodes into subsections
enum OpcodeClass {
@@ -159,6 +160,10 @@ enum OperandClass {
@@ -159,6 +163,10 @@ enum OperandClass {
OperandOpcode,
@ -286,8 +396,14 @@ index 78b1031..5984835 100644
OperandCount
};
@@ -257,3 +265,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..c856271 100644
index d7312f9..e1413bb 100644
--- a/tools/spirv/main.cpp
+++ b/tools/spirv/main.cpp
@@ -46,6 +46,7 @@ namespace spv {
@ -298,38 +414,62 @@ index d7312f9..c856271 100644
#include "disassemble.h"
#include "header.h"
#include "doc.h"
@@ -65,6 +66,7 @@ enum TOptions {
@@ -65,6 +66,8 @@ enum TOptions {
EOptionDisassemble = 0x004,
EOptionPrintHeader = 0x008,
EOptionPrintOclBuiltinsAsciidoc = 0x010,
+ EOptionPrintAssemblerTable = 0x020,
+ EOptionPrintOclInstructionsTable = 0x040,
};
std::string Filename;
@@ -89,6 +91,7 @@ void Usage()
" 'CL12': OpenCL 1.2 extended instructions documentation\n"
" 'CL20': OpenCL 2.0 extended instructions documentation\n"
" 'CL21': OpenCL 2.1 extended instructions documentation\n"
@@ -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 +158,9 @@ bool ProcessArguments(int argc, char* argv[])
@@ -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;
}
@@ -220,5 +226,8 @@ int main(int argc, char* argv[])
@@ -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;
}

217
test/ExtInst.OpenCL.std.cpp Normal file
View File

@ -0,0 +1,217 @@
// Copyright (c) 2015 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 "UnitSPIRV.h"
#include <gmock/gmock.h>
#include "TestFixture.h"
namespace {
using spvtest::Concatenate;
using spvtest::MakeInstruction;
using spvtest::MakeVector;
using testing::Eq;
struct InstructionCase {
uint32_t opcode;
std::string name;
std::string operands;
std::vector<uint32_t> expected_operands;
};
using ExtInstOpenCLStdRoundTripTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<InstructionCase>>;
TEST_P(ExtInstOpenCLStdRoundTripTest, ParameterizedExtInst) {
// This example should not validate.
const std::string input =
"%1 = OpExtInstImport \"OpenCL.std\"\n"
"%3 = OpExtInst %2 %1 " +
GetParam().name + " " + GetParam().operands + "\n";
// First make sure it assembles correctly.
EXPECT_THAT(
CompiledInstructions(input),
Eq(Concatenate(
{MakeInstruction(spv::OpExtInstImport, {1}, MakeVector("OpenCL.std")),
MakeInstruction(spv::OpExtInst, {2, 3, 1, GetParam().opcode},
GetParam().expected_operands)})))
<< input;
// Now check the round trip through the disassembler.
EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input) << input;
}
#define CASE1(Enum, Name) \
{ \
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4", { 4 } \
}
#define CASE2(Enum, Name) \
{ \
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5", { 4, 5 } \
}
#define CASE3(Enum, Name) \
{ \
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6", { 4, 5, 6 } \
}
// clang-format off
// OpenCL.std: 2.1 Math extended instructions
INSTANTIATE_TEST_CASE_P(
OpenCLMath, ExtInstOpenCLStdRoundTripTest,
::testing::ValuesIn(std::vector<InstructionCase>({
// We are only testing the correctness of encoding and decoding here.
// Semantic correctness should be the responsibility of validator.
CASE1(Acos, acos), // enum value 0
CASE1(Acosh, acosh),
CASE1(Acospi, acospi),
CASE1(Asin, asin),
CASE1(Asinh, asinh),
CASE1(Asinh, asinh),
CASE1(Asinpi, asinpi),
CASE1(Atan, atan),
CASE2(Atan2, atan2),
CASE1(Atanh, atanh),
CASE1(Atanpi, atanpi),
CASE2(Atan2pi, atan2pi),
CASE1(Cbrt, cbrt),
CASE1(Ceil, ceil),
CASE1(Ceil, ceil),
CASE2(Copysign, copysign),
CASE1(Cos, cos),
CASE1(Cosh, cosh),
CASE1(Cospi, cospi),
CASE1(Erfc, erfc),
CASE1(Erf, erf),
CASE1(Exp, exp),
CASE1(Exp2, exp2),
CASE1(Exp10, exp10),
CASE1(Expm1, expm1),
CASE1(Fabs, fabs),
CASE2(Fdim, fdim),
CASE1(Floor, floor),
CASE3(Fma, fma),
CASE2(Fmax, fmax),
CASE2(Fmin, fmin),
CASE2(Fmod, fmod),
CASE2(Fract, fract),
CASE2(Frexp, frexp),
CASE2(Hypot, hypot),
CASE1(Ilogb, ilogb),
CASE2(Ldexp, ldexp),
CASE1(Lgamma, lgamma),
CASE2(Lgamma_r, lgamma_r),
CASE1(Log, log),
CASE1(Log2, log2),
CASE1(Log10, log10),
CASE1(Log1p, log1p),
CASE3(Mad, mad),
CASE2(Maxmag, maxmag),
CASE2(Minmag, minmag),
CASE2(Modf, modf),
CASE1(Nan, nan),
CASE2(Nextafter, nextafter),
CASE3(Pow, pow),
CASE1(Pown, pown),
CASE2(Powr, powr),
CASE2(Remainder, remainder),
CASE3(Remquo, remquo),
CASE1(Rint, rint),
CASE2(Rootn, rootn),
CASE1(Round, round),
CASE1(Rsqrt, rsqrt),
CASE1(Sin, sin),
CASE2(Sincos, sincos),
CASE1(Sinh, sinh),
CASE1(Sinpi, sinpi),
CASE1(Sqrt, sqrt),
CASE1(Tan, tan),
CASE1(Tanh, tanh),
CASE1(Tanpi, tanpi),
CASE1(Tgamma, tgamma),
CASE1(Trunc, trunc),
CASE1(Half_cos, half_cos),
CASE2(Half_divide, half_divide),
CASE1(Half_exp, half_exp),
CASE1(Half_exp2, half_exp2),
CASE1(Half_exp10, half_exp10),
CASE1(Half_log, half_log),
CASE1(Half_log2, half_log2),
CASE1(Half_log10, half_log10),
CASE2(Half_powr, half_powr),
CASE1(Half_recip, half_recip),
CASE1(Half_rsqrt, half_rsqrt),
CASE1(Half_sin, half_sin),
CASE1(Half_sqrt, half_sqrt),
CASE1(Half_tan, half_tan),
CASE1(Native_cos, native_cos),
CASE2(Native_divide, native_divide),
CASE1(Native_exp, native_exp),
CASE1(Native_exp2, native_exp2),
CASE1(Native_exp10, native_exp10),
CASE1(Native_log, native_log),
CASE1(Native_log10, native_log10),
CASE2(Native_powr, native_powr),
CASE1(Native_recip, native_recip),
CASE1(Native_rsqrt, native_rsqrt),
CASE1(Native_sin, native_sin),
CASE1(Native_sqrt, native_sqrt),
CASE1(Native_tan, native_tan), // enum value 94
})));
// TODO(dneto): OpenCL.std: 2.1 Integer instructions
// OpenCL.std: 2.3 Common instrucitons
INSTANTIATE_TEST_CASE_P(
OpenCLCommon, ExtInstOpenCLStdRoundTripTest,
::testing::ValuesIn(std::vector<InstructionCase>({
CASE3(FClamp, fclamp), // enum value 95
CASE1(Degrees, degrees),
CASE2(FMax_common, fmax_common),
CASE2(FMin_common, fmin_common),
CASE3(Mix, mix),
CASE1(Radians, radians),
CASE2(Step, step),
CASE3(Smoothstep, smoothstep),
CASE1(Sign, sign), // enum value 103
})));
// TODO(dneto): OpenCL.std: 2.4 Geometric instructions
// TODO(dneto): OpenCL.std: 2.5 Relational instructions
// TODO(dneto): OpenCL.std: 2.6 Vector data load and store instructions
// TODO(dneto): OpenCL.std: 2.7 Miscellaneous vector instructions
// TODO(dneto): OpenCL.std: 2.8 Miscellaneous instructions
// TODO(dneto): OpenCL.std: 2.9.1 Image encoding
// TODO(dneto): OpenCL.std: 2.9.2 Sampler encoding
// TODO(dneto): OpenCL.std: 2.9.3 Image read
// TODO(dneto): OpenCL.std: 2.9.4 Image write
// clang-format on
#undef CASE1
#undef CASE2
#undef CASE3
} // anonymous namespace