summaryrefslogtreecommitdiff
path: root/source/val/validation_state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/val/validation_state.cpp')
-rw-r--r--source/val/validation_state.cpp389
1 files changed, 389 insertions, 0 deletions
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
new file mode 100644
index 00000000..11096bc3
--- /dev/null
+++ b/source/val/validation_state.cpp
@@ -0,0 +1,389 @@
+// Copyright (c) 2015-2016 The Khronos Group 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.
+
+#include "val/validation_state.h"
+
+#include <cassert>
+
+#include "val/basic_block.h"
+#include "val/construct.h"
+#include "val/function.h"
+
+using std::deque;
+using std::make_pair;
+using std::pair;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace libspirv {
+
+namespace {
+bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
+ // See Section 2.4
+ bool out = false;
+ // clang-format off
+ switch (layout) {
+ case kLayoutCapabilities: out = op == SpvOpCapability; break;
+ case kLayoutExtensions: out = op == SpvOpExtension; break;
+ case kLayoutExtInstImport: out = op == SpvOpExtInstImport; break;
+ case kLayoutMemoryModel: out = op == SpvOpMemoryModel; break;
+ case kLayoutEntryPoint: out = op == SpvOpEntryPoint; break;
+ case kLayoutExecutionMode: out = op == SpvOpExecutionMode; break;
+ case kLayoutDebug1:
+ switch (op) {
+ case SpvOpSourceContinued:
+ case SpvOpSource:
+ case SpvOpSourceExtension:
+ case SpvOpString:
+ out = true;
+ break;
+ default: break;
+ }
+ break;
+ case kLayoutDebug2:
+ switch (op) {
+ case SpvOpName:
+ case SpvOpMemberName:
+ out = true;
+ break;
+ default: break;
+ }
+ break;
+ case kLayoutAnnotations:
+ switch (op) {
+ case SpvOpDecorate:
+ case SpvOpMemberDecorate:
+ case SpvOpGroupDecorate:
+ case SpvOpGroupMemberDecorate:
+ case SpvOpDecorationGroup:
+ out = true;
+ break;
+ default: break;
+ }
+ break;
+ case kLayoutTypes:
+ switch (op) {
+ case SpvOpTypeVoid:
+ case SpvOpTypeBool:
+ case SpvOpTypeInt:
+ case SpvOpTypeFloat:
+ case SpvOpTypeVector:
+ case SpvOpTypeMatrix:
+ case SpvOpTypeImage:
+ case SpvOpTypeSampler:
+ case SpvOpTypeSampledImage:
+ case SpvOpTypeArray:
+ case SpvOpTypeRuntimeArray:
+ case SpvOpTypeStruct:
+ case SpvOpTypeOpaque:
+ case SpvOpTypePointer:
+ case SpvOpTypeFunction:
+ case SpvOpTypeEvent:
+ case SpvOpTypeDeviceEvent:
+ case SpvOpTypeReserveId:
+ case SpvOpTypeQueue:
+ case SpvOpTypePipe:
+ case SpvOpTypeForwardPointer:
+ case SpvOpConstantTrue:
+ case SpvOpConstantFalse:
+ case SpvOpConstant:
+ case SpvOpConstantComposite:
+ case SpvOpConstantSampler:
+ case SpvOpConstantNull:
+ case SpvOpSpecConstantTrue:
+ case SpvOpSpecConstantFalse:
+ case SpvOpSpecConstant:
+ case SpvOpSpecConstantComposite:
+ case SpvOpSpecConstantOp:
+ case SpvOpVariable:
+ case SpvOpLine:
+ case SpvOpNoLine:
+ case SpvOpUndef:
+ out = true;
+ break;
+ default: break;
+ }
+ break;
+ case kLayoutFunctionDeclarations:
+ case kLayoutFunctionDefinitions:
+ // NOTE: These instructions should NOT be in these layout sections
+ switch (op) {
+ case SpvOpCapability:
+ case SpvOpExtension:
+ case SpvOpExtInstImport:
+ case SpvOpMemoryModel:
+ case SpvOpEntryPoint:
+ case SpvOpExecutionMode:
+ case SpvOpSourceContinued:
+ case SpvOpSource:
+ case SpvOpSourceExtension:
+ case SpvOpString:
+ case SpvOpName:
+ case SpvOpMemberName:
+ case SpvOpDecorate:
+ case SpvOpMemberDecorate:
+ case SpvOpGroupDecorate:
+ case SpvOpGroupMemberDecorate:
+ case SpvOpDecorationGroup:
+ case SpvOpTypeVoid:
+ case SpvOpTypeBool:
+ case SpvOpTypeInt:
+ case SpvOpTypeFloat:
+ case SpvOpTypeVector:
+ case SpvOpTypeMatrix:
+ case SpvOpTypeImage:
+ case SpvOpTypeSampler:
+ case SpvOpTypeSampledImage:
+ case SpvOpTypeArray:
+ case SpvOpTypeRuntimeArray:
+ case SpvOpTypeStruct:
+ case SpvOpTypeOpaque:
+ case SpvOpTypePointer:
+ case SpvOpTypeFunction:
+ case SpvOpTypeEvent:
+ case SpvOpTypeDeviceEvent:
+ case SpvOpTypeReserveId:
+ case SpvOpTypeQueue:
+ case SpvOpTypePipe:
+ case SpvOpTypeForwardPointer:
+ case SpvOpConstantTrue:
+ case SpvOpConstantFalse:
+ case SpvOpConstant:
+ case SpvOpConstantComposite:
+ case SpvOpConstantSampler:
+ case SpvOpConstantNull:
+ case SpvOpSpecConstantTrue:
+ case SpvOpSpecConstantFalse:
+ case SpvOpSpecConstant:
+ case SpvOpSpecConstantComposite:
+ case SpvOpSpecConstantOp:
+ out = false;
+ break;
+ default:
+ out = true;
+ break;
+ }
+ }
+ // clang-format on
+ return out;
+}
+
+} // anonymous namespace
+
+ValidationState_t::ValidationState_t(const spv_const_context ctx)
+ : context_(ctx),
+ instruction_counter_(0),
+ unresolved_forward_ids_{},
+ operand_names_{},
+ current_layout_section_(kLayoutCapabilities),
+ module_functions_(),
+ module_capabilities_(),
+ ordered_instructions_(),
+ all_definitions_(),
+ grammar_(ctx),
+ addressing_model_(SpvAddressingModelLogical),
+ memory_model_(SpvMemoryModelSimple),
+ in_function_(false) {}
+
+spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
+ unresolved_forward_ids_.insert(id);
+ return SPV_SUCCESS;
+}
+
+spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
+ unresolved_forward_ids_.erase(id);
+ return SPV_SUCCESS;
+}
+
+void ValidationState_t::AssignNameToId(uint32_t id, string name) {
+ operand_names_[id] = name;
+}
+
+string ValidationState_t::getIdName(uint32_t id) const {
+ std::stringstream out;
+ out << id;
+ if (operand_names_.find(id) != end(operand_names_)) {
+ out << "[" << operand_names_.at(id) << "]";
+ }
+ return out.str();
+}
+
+string ValidationState_t::getIdOrName(uint32_t id) const {
+ std::stringstream out;
+ if (operand_names_.find(id) != end(operand_names_)) {
+ out << operand_names_.at(id);
+ } else {
+ out << id;
+ }
+ return out.str();
+}
+
+size_t ValidationState_t::unresolved_forward_id_count() const {
+ return unresolved_forward_ids_.size();
+}
+
+vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
+ vector<uint32_t> out(begin(unresolved_forward_ids_),
+ end(unresolved_forward_ids_));
+ return out;
+}
+
+bool ValidationState_t::IsDefinedId(uint32_t id) const {
+ return all_definitions_.find(id) != end(all_definitions_);
+}
+
+const Instruction* ValidationState_t::FindDef(uint32_t id) const {
+ if (all_definitions_.count(id) == 0) {
+ return nullptr;
+ } else {
+ /// We are in a const function, so we cannot use defs.operator[]().
+ /// Luckily we know the key exists, so defs_.at() won't throw an
+ /// exception.
+ return all_definitions_.at(id);
+ }
+}
+
+Instruction* ValidationState_t::FindDef(uint32_t id) {
+ if (all_definitions_.count(id) == 0) {
+ return nullptr;
+ } else {
+ /// We are in a const function, so we cannot use defs.operator[]().
+ /// Luckily we know the key exists, so defs_.at() won't throw an
+ /// exception.
+ return all_definitions_.at(id);
+ }
+}
+
+// Increments the instruction count. Used for diagnostic
+int ValidationState_t::increment_instruction_count() {
+ return instruction_counter_++;
+}
+
+ModuleLayoutSection ValidationState_t::current_layout_section() const {
+ return current_layout_section_;
+}
+
+void ValidationState_t::ProgressToNextLayoutSectionOrder() {
+ // Guard against going past the last element(kLayoutFunctionDefinitions)
+ if (current_layout_section_ <= kLayoutFunctionDefinitions) {
+ current_layout_section_ =
+ static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
+ }
+}
+
+bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
+ return IsInstructionInLayoutSection(current_layout_section_, op);
+}
+
+DiagnosticStream ValidationState_t::diag(spv_result_t error_code) const {
+ return libspirv::DiagnosticStream(
+ {0, 0, static_cast<size_t>(instruction_counter_)}, context_->consumer,
+ error_code);
+}
+
+deque<Function>& ValidationState_t::functions() { return module_functions_; }
+
+Function& ValidationState_t::current_function() {
+ assert(in_function_body());
+ return module_functions_.back();
+}
+
+bool ValidationState_t::in_function_body() const { return in_function_; }
+
+bool ValidationState_t::in_block() const {
+ return module_functions_.empty() == false &&
+ module_functions_.back().current_block() != nullptr;
+}
+
+void ValidationState_t::RegisterCapability(SpvCapability cap) {
+ // Avoid redundant work. Otherwise the recursion could induce work
+ // quadrdatic in the capability dependency depth. (Ok, not much, but
+ // it's something.)
+ if (module_capabilities_.Contains(cap)) return;
+
+ module_capabilities_.Add(cap);
+ spv_operand_desc desc;
+ if (SPV_SUCCESS ==
+ grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
+ desc->capabilities.ForEach(
+ [this](SpvCapability c) { RegisterCapability(c); });
+ }
+}
+
+bool ValidationState_t::HasAnyOf(const CapabilitySet& capabilities) const {
+ bool found = false;
+ bool any_queried = false;
+ capabilities.ForEach([&found, &any_queried, this](SpvCapability c) {
+ any_queried = true;
+ found = found || this->module_capabilities_.Contains(c);
+ });
+ return !any_queried || found;
+}
+
+void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
+ addressing_model_ = am;
+}
+
+SpvAddressingModel ValidationState_t::addressing_model() const {
+ return addressing_model_;
+}
+
+void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
+ memory_model_ = mm;
+}
+
+SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
+
+spv_result_t ValidationState_t::RegisterFunction(
+ uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
+ uint32_t function_type_id) {
+ assert(in_function_body() == false &&
+ "RegisterFunction can only be called when parsing the binary outside "
+ "of another function");
+ in_function_ = true;
+ module_functions_.emplace_back(id, ret_type_id, function_control,
+ function_type_id);
+
+ // TODO(umar): validate function type and type_id
+
+ return SPV_SUCCESS;
+}
+
+spv_result_t ValidationState_t::RegisterFunctionEnd() {
+ assert(in_function_body() == true &&
+ "RegisterFunctionEnd can only be called when parsing the binary "
+ "inside of another function");
+ assert(in_block() == false &&
+ "RegisterFunctionParameter can only be called when parsing the binary "
+ "ouside of a block");
+ current_function().RegisterFunctionEnd();
+ in_function_ = false;
+ return SPV_SUCCESS;
+}
+
+void ValidationState_t::RegisterInstruction(
+ const spv_parsed_instruction_t& inst) {
+ if (in_function_body()) {
+ ordered_instructions_.emplace_back(&inst, &current_function(),
+ current_function().current_block());
+ } else {
+ ordered_instructions_.emplace_back(&inst, nullptr, nullptr);
+ }
+ uint32_t id = ordered_instructions_.back().id();
+ if (id) {
+ all_definitions_.insert(make_pair(id, &ordered_instructions_.back()));
+ }
+}
+} /// namespace libspirv