blob: f5bfc041cb03506b407dd4e560a6dd2067998d17 [file] [log] [blame]
// Copyright 2020 The Tint Authors.
// 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
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "source/opt/constants.h"
#include "source/opt/decoration_manager.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "source/opt/type_manager.h"
#include "spirv-tools/libspirv.hpp"
#include "src/ast/import.h"
#include "src/ast/module.h"
#include "src/ast/type/type.h"
#include "src/reader/reader.h"
#include "src/reader/spirv/enum_converter.h"
#include "src/reader/spirv/fail_stream.h"
#include "src/reader/spirv/namer.h"
namespace tint {
namespace reader {
namespace spirv {
/// Parser implementation for SPIR-V.
class ParserImpl : Reader {
/// Creates a new parser
/// @param input the input data to parse
explicit ParserImpl(const std::vector<uint32_t>& input);
/// Destructor
~ParserImpl() override;
/// Run the parser
/// @returns true if the parse was successful, false otherwise.
bool Parse() override;
/// @returns the module. The module in the parser will be reset after this.
ast::Module module() override;
/// Logs failure, ands return a failure stream to accumulate diagnostic
/// messages. By convention, a failure should only be logged along with
/// a non-empty string diagnostic.
/// @returns the failure stream
FailStream& Fail() {
success_ = false;
return fail_stream_;
/// @returns the accumulated error string
const std::string error() { return errors_.str(); }
/// Builds an internal representation of the SPIR-V binary,
/// and parses it into a Tint AST module. Diagnostics are emitted
/// to the error stream.
/// @returns true if it was successful.
bool BuildAndParseInternalModule() {
return BuildInternalModule() && ParseInternalModule();
/// @returns the set of SPIR-V IDs for imports of the "GLSL.std.450"
/// extended instruction set.
const std::unordered_set<uint32_t>& glsl_std_450_imports() const {
return glsl_std_450_imports_;
/// Converts a SPIR-V type to a Tint type.
/// On failure, logs an error and returns null.
/// This should only be called after the internal
/// representation of the module has been built.
/// @param type_id the SPIR-V ID of a type.
/// @returns a Tint type, or nullptr
ast::type::Type* ConvertType(uint32_t type_id);
/// @returns the namer object
Namer& namer() { return namer_; }
/// Builds the internal representation of the SPIR-V module.
/// Assumes the module is somewhat well-formed. Normally you
/// would want to validate the SPIR-V module before attempting
/// to build this internal representation.
/// @returns true if successful.
bool BuildInternalModule();
/// Walks the internal representation of the module to populate
/// the AST form of the module.
/// @returns true on success
bool ParseInternalModule();
/// Destroys the internal representation of the SPIR-V module.
void ResetInternalModule();
/// Registers extended instruction imports. Only "GLSL.std.450" is supported.
bool RegisterExtendedInstructionImports();
/// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
/// Also synthesizes struct field names. Ensures uniqueness for names for
/// SPIR-V IDs, and uniqueness of names of fields within any single struct.
bool RegisterUserNames();
/// Emit entry point AST nodes.
bool EmitEntryPoints();
// The SPIR-V binary we're parsing
std::vector<uint32_t> spv_binary_;
// The resulting module in Tint AST form.
ast::Module ast_module_;
// Is the parse successful?
bool success_ = true;
// Collector for diagnostic messages.
std::stringstream errors_;
FailStream fail_stream_;
spvtools::MessageConsumer message_consumer_;
// An object used to store and generate names for SPIR-V objects.
Namer namer_;
// An object used to convert SPIR-V enums to Tint enums
EnumConverter enum_converter_;
// The internal representation of the SPIR-V module and its context.
spvtools::Context tools_context_;
spvtools::SpirvTools tools_;
// All the state is owned by ir_context_.
std::unique_ptr<spvtools::opt::IRContext> ir_context_;
// The following are borrowed pointers to the internal state of ir_context_.
spvtools::opt::Module* module_ = nullptr;
spvtools::opt::analysis::DefUseManager* def_use_mgr_ = nullptr;
spvtools::opt::analysis::ConstantManager* constant_mgr_ = nullptr;
spvtools::opt::analysis::TypeManager* type_mgr_ = nullptr;
spvtools::opt::analysis::DecorationManager* deco_mgr_ = nullptr;
/// Maps a SPIR-V ID for an external instruction import to an AST import
std::unordered_map<uint32_t, ast::Import*> import_map_;
// The set of IDs that are imports of the GLSL.std.450 extended instruction
// sets.
std::unordered_set<uint32_t> glsl_std_450_imports_;
// Maps a SPIR-V type ID to a Tint type.
std::unordered_map<uint32_t, ast::type::Type*> id_to_type_;
} // namespace spirv
} // namespace reader
} // namespace tint