return spvValidateBinary(context, binary->code, binary->wordCount,
pDiagnostic);
}
-spv_result_t spvValidateBinary(const spv_const_context context,
- const uint32_t* words, const size_t num_words,
- spv_diagnostic* pDiagnostic) {
- spv_context_t hijack_context = *context;
+spv_result_t ValidateBinaryUsingContextAndValidationState(
+ const spv_context_t& context, const uint32_t* words, const size_t num_words,
+ spv_diagnostic* pDiagnostic, ValidationState_t* vstate) {
spv_const_binary binary = new spv_const_binary_t{words, num_words};
- if (pDiagnostic) {
- *pDiagnostic = nullptr;
- libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
- }
spv_endianness_t endian;
spv_position_t position = {};
if (spvBinaryEndianness(binary, &endian)) {
- return libspirv::DiagnosticStream(position, hijack_context.consumer,
+ return libspirv::DiagnosticStream(position, context.consumer,
SPV_ERROR_INVALID_BINARY)
<< "Invalid SPIR-V magic number.";
}
spv_header_t header;
if (spvBinaryHeaderGet(binary, endian, &header)) {
- return libspirv::DiagnosticStream(position, hijack_context.consumer,
+ return libspirv::DiagnosticStream(position, context.consumer,
SPV_ERROR_INVALID_BINARY)
<< "Invalid SPIR-V header.";
}
// NOTE: Parse the module and perform inline validation checks. These
// checks do not require the the knowledge of the whole module.
- ValidationState_t vstate(&hijack_context);
- if (auto error = spvBinaryParse(&hijack_context, &vstate, words, num_words,
+ if (auto error = spvBinaryParse(&context, vstate, words, num_words,
setHeader, ProcessInstruction, pDiagnostic))
return error;
- if (vstate.in_function_body())
- return vstate.diag(SPV_ERROR_INVALID_LAYOUT)
+ if (vstate->in_function_body())
+ return vstate->diag(SPV_ERROR_INVALID_LAYOUT)
<< "Missing OpFunctionEnd at end of module.";
// TODO(umar): Add validation checks which require the parsing of the entire
// module. Use the information from the ProcessInstruction pass to make the
// checks.
- if (vstate.unresolved_forward_id_count() > 0) {
+ if (vstate->unresolved_forward_id_count() > 0) {
stringstream ss;
- vector<uint32_t> ids = vstate.UnresolvedForwardIds();
+ vector<uint32_t> ids = vstate->UnresolvedForwardIds();
transform(begin(ids), end(ids), ostream_iterator<string>(ss, " "),
- bind(&ValidationState_t::getIdName, std::ref(vstate), _1));
+ bind(&ValidationState_t::getIdName, std::ref(*vstate), _1));
auto id_str = ss.str();
- return vstate.diag(SPV_ERROR_INVALID_ID)
+ return vstate->diag(SPV_ERROR_INVALID_ID)
<< "The following forward referenced IDs have not been defined:\n"
<< id_str.substr(0, id_str.size() - 1);
}
// CFG checks are performed after the binary has been parsed
// and the CFGPass has collected information about the control flow
- if (auto error = PerformCfgChecks(vstate)) return error;
- if (auto error = UpdateIdUse(vstate)) return error;
- if (auto error = CheckIdDefinitionDominateUse(vstate)) return error;
+ if (auto error = PerformCfgChecks(*vstate)) return error;
+ if (auto error = UpdateIdUse(*vstate)) return error;
+ if (auto error = CheckIdDefinitionDominateUse(*vstate)) return error;
// NOTE: Copy each instruction for easier processing
std::vector<spv_instruction_t> instructions;
position.index = SPV_INDEX_INSTRUCTION;
return spvValidateIDs(instructions.data(), instructions.size(),
- hijack_context.opcode_table,
- hijack_context.operand_table,
- hijack_context.ext_inst_table, vstate, &position);
+ context.opcode_table,
+ context.operand_table,
+ context.ext_inst_table, *vstate, &position);
}
+
+spv_result_t spvValidateBinary(const spv_const_context context,
+ const uint32_t* words, const size_t num_words,
+ spv_diagnostic* pDiagnostic) {
+ spv_context_t hijack_context = *context;
+ if (pDiagnostic) {
+ *pDiagnostic = nullptr;
+ libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
+ }
+
+ // Create the ValidationState using the context.
+ ValidationState_t vstate(&hijack_context);
+
+ return ValidateBinaryUsingContextAndValidationState(
+ hijack_context, words, num_words, pDiagnostic, &vstate);
+}
+
+spv_result_t spvtools::ValidateBinaryAndKeepValidationState(
+ const spv_const_context context, const uint32_t* words,
+ const size_t num_words, spv_diagnostic* pDiagnostic,
+ std::unique_ptr<ValidationState_t>* vstate) {
+ spv_context_t hijack_context = *context;
+ if (pDiagnostic) {
+ *pDiagnostic = nullptr;
+ libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
+ }
+
+ vstate->reset(new ValidationState_t(&hijack_context));
+ return ValidateBinaryUsingContextAndValidationState(
+ hijack_context, words, num_words, pDiagnostic, vstate->get());
+}
+
--- /dev/null
+// Copyright (c) 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Basic tests for the ValidationState_t datastructure.
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "unit_spirv.h"
+#include "val_fixtures.h"
+
+namespace {
+
+using std::string;
+using ::testing::HasSubstr;
+
+using ValidationStateTest = spvtest::ValidateBase<bool>;
+
+const char header[] =
+ " OpCapability Shader"
+ " OpCapability Linkage"
+ " OpMemoryModel Logical GLSL450 ";
+
+const char kVoidFVoid[] =
+ " %void = OpTypeVoid"
+ " %void_f = OpTypeFunction %void"
+ " %func = OpFunction %void None %void_f"
+ " %label = OpLabel"
+ " OpReturn"
+ " OpFunctionEnd ";
+
+// Tests that the instruction count in ValidationState is correct.
+TEST_F(ValidationStateTest, CheckNumInstructions) {
+ string spirv = string(header) + "%int = OpTypeInt 32 0";
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+ EXPECT_EQ(size_t(4), vstate_->ordered_instructions().size());
+}
+
+// Tests that the number of global variables in ValidationState is correct.
+TEST_F(ValidationStateTest, CheckNumGlobalVars) {
+ string spirv = string(header) + R"(
+ %int = OpTypeInt 32 0
+%_ptr_int = OpTypePointer Input %int
+ %var_1 = OpVariable %_ptr_int Input
+ %var_2 = OpVariable %_ptr_int Input
+ )";
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+ EXPECT_EQ(unsigned(2), vstate_->num_global_vars());
+}
+
+// Tests that the number of local variables in ValidationState is correct.
+TEST_F(ValidationStateTest, CheckNumLocalVars) {
+ string spirv = string(header) + R"(
+ %int = OpTypeInt 32 0
+ %_ptr_int = OpTypePointer Function %int
+ %voidt = OpTypeVoid
+ %funct = OpTypeFunction %voidt
+ %main = OpFunction %voidt None %funct
+ %entry = OpLabel
+ %var_1 = OpVariable %_ptr_int Function
+ %var_2 = OpVariable %_ptr_int Function
+ %var_3 = OpVariable %_ptr_int Function
+ OpReturn
+ OpFunctionEnd
+ )";
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+ EXPECT_EQ(unsigned(3), vstate_->num_local_vars());
+}
+
+// Tests that the "id bound" in ValidationState is correct.
+TEST_F(ValidationStateTest, CheckIdBound) {
+ string spirv = string(header) + R"(
+ %int = OpTypeInt 32 0
+ %voidt = OpTypeVoid
+ )";
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+ EXPECT_EQ(unsigned(3), vstate_->getIdBound());
+}
+
+// Tests that the entry_points in ValidationState is correct.
+TEST_F(ValidationStateTest, CheckEntryPoints) {
+ string spirv = string(header) + " OpEntryPoint Vertex %func \"shader\"" +
+ string(kVoidFVoid);
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+ EXPECT_EQ(size_t(1), vstate_->entry_points().size());
+ EXPECT_EQ(SpvOpFunction,
+ vstate_->FindDef(vstate_->entry_points()[0])->opcode());
+}
+
+} // anonymous namespace