${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.DeviceSideEnqueue.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Extension.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Function.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Group.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Image.cpp
} spv_operand_type_t;
typedef enum spv_ext_inst_type_t {
- SPV_EXT_INST_TYPE_NONE,
+ SPV_EXT_INST_TYPE_NONE = 0,
SPV_EXT_INST_TYPE_GLSL_STD_450,
SPV_EXT_INST_TYPE_OPENCL_STD,
const uint32_t id = context->spvNamedIdAssignOrGet(textValue);
if (type == SPV_OPERAND_TYPE_TYPE_ID) pInst->resultTypeId = id;
spvInstructionAddWord(pInst, id);
+
+ // Set the extended instruction type.
+ // The import set id is the 3rd operand of OpExtInst.
+ if (pInst->opcode == SpvOpExtInst && pInst->words.size() == 4) {
+ auto ext_inst_type = context->getExtInstTypeForId(pInst->words[3]);
+ if (ext_inst_type == SPV_EXT_INST_TYPE_NONE) {
+ return context->diagnostic()
+ << "Invalid extended instruction import Id "
+ << pInst->words[2];
+ }
+ pInst->extInstType = ext_inst_type;
+ }
+
} break;
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
// NOTE: Special case for extended instruction library import
if (SpvOpExtInstImport == pInst->opcode) {
- pInst->extInstType = spvExtInstImportTypeGet(literal.value.str);
+ const spv_ext_inst_type_t ext_inst_type =
+ spvExtInstImportTypeGet(literal.value.str);
+ if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
+ return context->diagnostic()
+ << "Invalid extended instruction import '" << literal.value.str
+ << "'";
+ }
+ if (auto error = context->recordIdAsExtInstImport(pInst->words[1], ext_inst_type))
+ return error;
}
if (context->binaryEncodeString(literal.value.str, pInst))
// Skip past whitespace and comments.
context.advance();
- spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
while (context.hasText()) {
instructions.push_back({});
spv_instruction_t& inst = instructions.back();
- inst.extInstType = extInstType;
if (spvTextEncodeOpcode(grammar, &context, &inst)) {
return SPV_ERROR_INVALID_TEXT;
}
- extInstType = inst.extInstType;
if (context.advance()) break;
}
return SPV_SUCCESS;
}
+spv_result_t AssemblyContext::recordIdAsExtInstImport(
+ uint32_t id, spv_ext_inst_type_t type) {
+ bool successfully_inserted = false;
+ std::tie(std::ignore, successfully_inserted) =
+ import_id_to_ext_inst_type_.insert(std::make_pair(id, type));
+ if (!successfully_inserted)
+ return diagnostic() << "Import Id is being defined a second time";
+ return SPV_SUCCESS;
+}
+
+spv_ext_inst_type_t AssemblyContext::getExtInstTypeForId(uint32_t id) const {
+ auto type = import_id_to_ext_inst_type_.find(id);
+ if (type == import_id_to_ext_inst_type_.end()) {
+ return SPV_EXT_INST_TYPE_NONE;
+ }
+ return std::get<1>(*type);
+}
+
spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
const char* val, spv_result_t error_code, const IdType& type,
spv_instruction_t* pInst) {
// Tracks the relationship between the value and its type.
spv_result_t recordTypeIdForValue(uint32_t value, uint32_t type);
+ // Records the given Id as being the import of the given extended instruction
+ // type.
+ spv_result_t recordIdAsExtInstImport(uint32_t id, spv_ext_inst_type_t type);
+
+ // Returns the extended instruction type corresponding to the import with
+ // the given Id, if it exists. Returns SPV_EXT_INST_TYPE_NONE if the
+ // id is not the id for an extended instruction type.
+ spv_ext_inst_type_t getExtInstTypeForId(uint32_t id) const;
+
// Parses a numeric value of a given type from the given text. The number
// should take up the entire string, and should be within bounds for the
// target type. On success, returns SPV_SUCCESS and populates the object
spv_named_id_table named_ids_;
spv_id_to_type_map types_;
spv_id_to_type_id value_types_;
+ // Maps an extended instruction import Id to the extended instruction type.
+ std::unordered_map<uint32_t, spv_ext_inst_type_t> import_id_to_ext_inst_type_;
spv_position_t current_position_;
spv_diagnostic* pDiagnostic_;
spv_text text_;
#undef CASE2Lit
#undef CASE3Round
-// TODO(dneto): Fix this functionality.
-TEST_F(TextToBinaryTest, DISABLED_ExtInstFromTwoDifferentImports) {
- const std::string input =
- R"(%1 = OpExtInstImport "OpenCL.std"
-%2 = OpExtInstImport "GLSL.std.450"
-%4 = OpExtInst %3 %1 native_sqrt %5
-%7 = OpExtInst %6 %2 MatrixInverse %8
-)";
- EXPECT_THAT(
- CompiledInstructions(input),
- Eq(Concatenate({
- MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
- MakeInstruction(SpvOpExtInstImport, {2}, MakeVector("GLSL.std.450")),
- MakeInstruction(
- SpvOpExtInst,
- {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
- MakeInstruction(SpvOpExtInst,
- {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
- })));
-}
-
} // anonymous namespace
--- /dev/null
+// 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.
+
+// Assembler tests for instructions in the "Extension Instruction" section
+// of the SPIR-V spec.
+
+#include "UnitSPIRV.h"
+
+#include "TestFixture.h"
+#include "gmock/gmock.h"
+
+namespace {
+
+using spvtest::Concatenate;
+using spvtest::MakeInstruction;
+using spvtest::MakeVector;
+using spvtest::TextToBinaryTest;
+using ::testing::Eq;
+
+TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
+ EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
+ Eq("Invalid extended instruction import 'Haskell.std'"));
+}
+
+TEST_F(TextToBinaryTest, InvalidImportId) {
+ EXPECT_THAT(CompileFailure("%1 = OpTypeVoid\n"
+ "%2 = OpExtInst %1 %1"),
+ Eq("Invalid extended instruction import Id 2"));
+}
+
+TEST_F(TextToBinaryTest, InvalidImportInstruction) {
+ const std::string input = R"(%1 = OpTypeVoid
+ %2 = OpExtInstImport "OpenCL.std"
+ %3 = OpExtInst %1 %2 not_in_the_opencl)";
+ EXPECT_THAT(CompileFailure(input),
+ Eq("Invalid extended instruction name 'not_in_the_opencl'."));
+}
+
+TEST_F(TextToBinaryTest, MultiImport) {
+ const std::string input = R"(%2 = OpExtInstImport "OpenCL.std"
+ %2 = OpExtInstImport "OpenCL.std")";
+ EXPECT_THAT(CompileFailure(input),
+ Eq("Import Id is being defined a second time"));
+}
+
+TEST_F(TextToBinaryTest, ExtInstFromTwoDifferentImports) {
+ const std::string input = R"(%1 = OpExtInstImport "OpenCL.std"
+%2 = OpExtInstImport "GLSL.std.450"
+%4 = OpExtInst %3 %1 native_sqrt %5
+%7 = OpExtInst %6 %2 MatrixInverse %8
+)";
+
+ // Make sure it assembles correctly.
+ EXPECT_THAT(
+ CompiledInstructions(input),
+ Eq(Concatenate({
+ MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
+ MakeInstruction(SpvOpExtInstImport, {2}, MakeVector("GLSL.std.450")),
+ MakeInstruction(
+ SpvOpExtInst,
+ {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
+ MakeInstruction(SpvOpExtInst,
+ {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
+ })));
+
+ // Make sure it disassembles correctly.
+ EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
+}
+
+} // anonymous namespace