Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2022-01-28 20:07:21 -08:00
parent 1776c3ae18
commit e8abac2374
85 changed files with 733 additions and 214 deletions

View File

@@ -1 +1 @@
"v2021.5-dev", "SPIRV-Tools v2021.5-dev 4581f14cd481bad1e0d6292f0dd0a6e298c2ee18"
"v2022.2-dev", "SPIRV-Tools v2022.2-dev 2e9ea79f27f42b1ea49e66ce7ba0a5c1ab75ea81"

View File

@@ -483,6 +483,7 @@ SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionDetailsString(void);
// SPV_ENV_VULKAN_1_1 -> SPIR-V 1.3
// SPV_ENV_VULKAN_1_1_SPIRV_1_4 -> SPIR-V 1.4
// SPV_ENV_VULKAN_1_2 -> SPIR-V 1.5
// SPV_ENV_VULKAN_1_3 -> SPIR-V 1.6
// Consult the description of API entry points for specific rules.
typedef enum {
SPV_ENV_UNIVERSAL_1_0, // SPIR-V 1.0 latest revision, no other restrictions.
@@ -519,7 +520,9 @@ typedef enum {
SPV_ENV_VULKAN_1_2, // Vulkan 1.2 latest revision.
SPV_ENV_UNIVERSAL_1_6, // SPIR-V 1.6 latest revision, no other restrictions.
SPV_ENV_MAX // Keep this as the last enum value.
SPV_ENV_VULKAN_1_3, // Vulkan 1.3 latest revision.
SPV_ENV_MAX // Keep this as the last enum value.
} spv_target_env;
// SPIR-V Validator can be parameterized with the following Universal Limits.
@@ -558,7 +561,7 @@ SPIRV_TOOLS_EXPORT bool spvParseVulkanEnv(uint32_t vulkan_ver,
// Creates a context object for most of the SPIRV-Tools API.
// Returns null if env is invalid.
//
// See specific API calls for how the target environment is interpeted
// See specific API calls for how the target environment is interpreted
// (particularly assembly and validation).
SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env);
@@ -610,7 +613,7 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxLogicalPointer(
// set that option.
// 2) Pointers that are pass as parameters to function calls do not have to
// match the storage class of the formal parameter.
// 3) Pointers that are actaul parameters on function calls do not have to point
// 3) Pointers that are actual parameters on function calls do not have to point
// to the same type pointed as the formal parameter. The types just need to
// logically match.
// 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant
@@ -636,7 +639,7 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout(
// Records whether the validator should use "scalar" block layout rules.
// Scalar layout rules are more permissive than relaxed block layout.
//
// See Vulkan extnesion VK_EXT_scalar_block_layout. The scalar alignment is
// See Vulkan extension VK_EXT_scalar_block_layout. The scalar alignment is
// defined as follows:
// - scalar alignment of a scalar is the scalar size
// - scalar alignment of a vector is the scalar alignment of its component

View File

@@ -36,7 +36,7 @@ class Context {
public:
// Constructs a context targeting the given environment |env|.
//
// See specific API calls for how the target environment is interpeted
// See specific API calls for how the target environment is interpreted
// (particularly assembly and validation).
//
// The constructed instance will have an empty message consumer, which just
@@ -139,7 +139,7 @@ class ValidatorOptions {
// set that option.
// 2) Pointers that are pass as parameters to function calls do not have to
// match the storage class of the formal parameter.
// 3) Pointers that are actaul parameters on function calls do not have to
// 3) Pointers that are actual parameters on function calls do not have to
// point to the same type pointed as the formal parameter. The types just
// need to logically match.
// 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant

View File

@@ -43,7 +43,7 @@ class Optimizer {
// consumed by the RegisterPass() method. Tokens are one-time objects that
// only support move; copying is not allowed.
struct PassToken {
struct Impl; // Opaque struct for holding inernal data.
struct Impl; // Opaque struct for holding internal data.
PassToken(std::unique_ptr<Impl>);
@@ -227,7 +227,7 @@ Optimizer::PassToken CreateNullPass();
// Creates a strip-debug-info pass.
// A strip-debug-info pass removes all debug instructions (as documented in
// Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
// Section 3.42.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
Optimizer::PassToken CreateStripDebugInfoPass();
// [Deprecated] This will create a strip-nonsemantic-info pass. See below.
@@ -296,11 +296,11 @@ Optimizer::PassToken CreateFreezeSpecConstantValuePass();
// and can be changed in future. A spec constant is foldable if all of its
// value(s) can be determined from the module. E.g., an integer spec constant
// defined with OpSpecConstantOp instruction can be folded if its value won't
// change later. This pass will replace the original OpSpecContantOp instruction
// with an OpConstant instruction. When folding composite spec constants,
// new instructions may be inserted to define the components of the composite
// constant first, then the original spec constants will be replaced by
// OpConstantComposite instructions.
// change later. This pass will replace the original OpSpecConstantOp
// instruction with an OpConstant instruction. When folding composite spec
// constants, new instructions may be inserted to define the components of the
// composite constant first, then the original spec constants will be replaced
// by OpConstantComposite instructions.
//
// There are some operations not supported yet:
// OpSConvert, OpFConvert, OpQuantizeToF16 and
@@ -326,7 +326,7 @@ Optimizer::PassToken CreateUnifyConstantPass();
// Creates a eliminate-dead-constant pass.
// A eliminate-dead-constant pass removes dead constants, including normal
// contants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
// constants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
// OpConstantFalse and spec constants defined by OpSpecConstant,
// OpSpecConstantComposite, OpSpecConstantTrue, OpSpecConstantFalse or
// OpSpecConstantOp.
@@ -390,7 +390,7 @@ Optimizer::PassToken CreateInlineOpaquePass();
// Only modules with relaxed logical addressing (see opt/instruction.h) are
// currently processed.
//
// This pass is most effective if preceeded by Inlining and
// This pass is most effective if preceded by Inlining and
// LocalAccessChainConvert. This pass will reduce the work needed to be done
// by LocalSingleStoreElim and LocalMultiStoreElim.
//
@@ -408,7 +408,7 @@ Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass();
// Note that some branches and blocks may be left to avoid creating invalid
// control flow. Improving this is left to future work.
//
// This pass is most effective when preceeded by passes which eliminate
// This pass is most effective when preceded by passes which eliminate
// local loads and stores, effectively propagating constant values where
// possible.
Optimizer::PassToken CreateDeadBranchElimPass();
@@ -425,7 +425,7 @@ Optimizer::PassToken CreateDeadBranchElimPass();
// are currently processed. Currently modules with any extensions enabled are
// not processed. This is left for future work.
//
// This pass is most effective if preceeded by Inlining and
// This pass is most effective if preceded by Inlining and
// LocalAccessChainConvert. LocalSingleStoreElim and LocalSingleBlockElim
// will reduce the work that this pass has to do.
Optimizer::PassToken CreateLocalMultiStoreElimPass();
@@ -630,7 +630,7 @@ Optimizer::PassToken CreateRedundancyEliminationPass();
Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit = 100);
// Create a private to local pass.
// This pass looks for variables delcared in the private storage class that are
// This pass looks for variables declared in the private storage class that are
// used in only one function. Those variables are moved to the function storage
// class in the function that they are used.
Optimizer::PassToken CreatePrivateToLocalPass();
@@ -835,6 +835,19 @@ Optimizer::PassToken CreateFixStorageClassPass();
// inclusive.
Optimizer::PassToken CreateGraphicsRobustAccessPass();
// Create a pass to spread Volatile semantics to variables with SMIDNV,
// WarpIDNV, SubgroupSize, SubgroupLocalInvocationId, SubgroupEqMask,
// SubgroupGeMask, SubgroupGtMask, SubgroupLeMask, or SubgroupLtMask BuiltIn
// decorations or OpLoad for them when the shader model is the ray generation,
// closest hit, miss, intersection, or callable. This pass can be used for
// VUID-StandaloneSpirv-VulkanMemoryModel-04678 and
// VUID-StandaloneSpirv-VulkanMemoryModel-04679 (See "Standalone SPIR-V
// Validation" section of Vulkan spec "Appendix A: Vulkan Environment for
// SPIR-V"). When the SPIR-V version is 1.6 or above, the pass also spreads
// the Volatile semantics to a variable with HelperInvocation BuiltIn decoration
// in the fragement shader.
Optimizer::PassToken CreateSpreadVolatileSemanticsPass();
// Create a pass to replace a descriptor access using variable index.
// This pass replaces every access using a variable index to array variable
// |desc| that has a DescriptorSet and Binding decorations with a constant

View File

@@ -215,7 +215,7 @@ class Parser {
size_t word_index; // The current position in words.
size_t instruction_count; // The count of processed instructions
spv_endianness_t endian; // The endianness of the binary.
// Is the SPIR-V binary in a different endiannes from the host native
// Is the SPIR-V binary in a different endianness from the host native
// endianness?
bool requires_endian_conversion;

View File

@@ -97,6 +97,7 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable,
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
*pExtInstTable = &kTable_1_0;
return SPV_SUCCESS;
default:

View File

@@ -27,7 +27,7 @@ bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type);
// Returns true if the extended instruction set is debug info
bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type);
// Finds the named extented instruction of the given type in the given extended
// Finds the named extended instruction of the given type in the given extended
// instruction table. On success, returns SPV_SUCCESS and writes a handle of
// the instruction entry into *entry.
spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
@@ -35,7 +35,7 @@ spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
const char* name,
spv_ext_inst_desc* entry);
// Finds the extented instruction of the given type in the given extended
// Finds the extended instruction of the given type in the given extended
// instruction table by value. On success, returns SPV_SUCCESS and writes a
// handle of the instruction entry into *entry.
spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,

View File

@@ -19,6 +19,7 @@
#include <cstring>
#include <iostream>
#include <memory>
#include <numeric>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -87,10 +88,6 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
//
// |header| should not be null, |modules| should not be empty and pointers
// should be non-null. |max_id_bound| should be strictly greater than 0.
//
// TODO(pierremoreau): What to do when binaries use different versions of
// SPIR-V? For now, use the max of all versions found in
// the input modules.
spv_result_t GenerateHeader(const MessageConsumer& consumer,
const std::vector<opt::Module*>& modules,
uint32_t max_id_bound, opt::ModuleHeader* header);
@@ -131,7 +128,7 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer,
// Remove linkage specific instructions, such as prototypes of imported
// functions, declarations of imported variables, import (and export if
// necessary) linkage attribtes.
// necessary) linkage attributes.
//
// |linked_context| and |decoration_manager| should not be null, and the
// 'RemoveDuplicatePass' should be run first.
@@ -149,6 +146,15 @@ spv_result_t RemoveLinkageSpecificInstructions(
spv_result_t VerifyIds(const MessageConsumer& consumer,
opt::IRContext* linked_context);
// Verify that the universal limits are not crossed, and warn the user
// otherwise.
//
// TODO(pierremoreau):
// - Verify against the limits of the environment (e.g. Vulkan limits if
// consuming vulkan1.x)
spv_result_t VerifyLimits(const MessageConsumer& consumer,
const opt::IRContext& linked_context);
spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
std::vector<opt::Module*>* modules,
uint32_t* max_id_bound) {
@@ -164,29 +170,31 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
<< "|max_id_bound| of ShiftIdsInModules should not be null.";
uint32_t id_bound = modules->front()->IdBound() - 1u;
const size_t id_bound =
std::accumulate(modules->begin(), modules->end(), static_cast<size_t>(1),
[](const size_t& accumulation, opt::Module* module) {
return accumulation + module->IdBound() - 1u;
});
if (id_bound > std::numeric_limits<uint32_t>::max())
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
<< "Too many IDs (" << id_bound
<< "): combining all modules would overflow the 32-bit word of the "
"SPIR-V header.";
*max_id_bound = static_cast<uint32_t>(id_bound);
uint32_t id_offset = modules->front()->IdBound() - 1u;
for (auto module_iter = modules->begin() + 1; module_iter != modules->end();
++module_iter) {
Module* module = *module_iter;
module->ForEachInst([&id_bound](Instruction* insn) {
insn->ForEachId([&id_bound](uint32_t* id) { *id += id_bound; });
module->ForEachInst([&id_offset](Instruction* insn) {
insn->ForEachId([&id_offset](uint32_t* id) { *id += id_offset; });
});
id_bound += module->IdBound() - 1u;
if (id_bound > 0x3FFFFF)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID)
<< "The limit of IDs, 4194303, was exceeded:"
<< " " << id_bound << " is the current ID bound.";
id_offset += module->IdBound() - 1u;
// Invalidate the DefUseManager
module->context()->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse);
}
++id_bound;
if (id_bound > 0x3FFFFF)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID)
<< "The limit of IDs, 4194303, was exceeded:"
<< " " << id_bound << " is the current ID bound.";
*max_id_bound = id_bound;
return SPV_SUCCESS;
}
@@ -203,12 +211,22 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer,
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA)
<< "|max_id_bound| of GenerateHeader should not be null.";
uint32_t version = 0u;
for (const auto& module : modules)
version = std::max(version, module->version());
const uint32_t linked_version = modules.front()->version();
for (std::size_t i = 1; i < modules.size(); ++i) {
const uint32_t module_version = modules[i]->version();
if (module_version != linked_version)
return DiagnosticStream({0, 0, 1}, consumer, "", SPV_ERROR_INTERNAL)
<< "Conflicting SPIR-V versions: "
<< SPV_SPIRV_VERSION_MAJOR_PART(linked_version) << "."
<< SPV_SPIRV_VERSION_MINOR_PART(linked_version)
<< " (input modules 1 through " << i << ") vs "
<< SPV_SPIRV_VERSION_MAJOR_PART(module_version) << "."
<< SPV_SPIRV_VERSION_MINOR_PART(module_version)
<< " (input module " << (i + 1) << ").";
}
header->magic_number = SpvMagicNumber;
header->version = version;
header->version = linked_version;
header->generator = SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_LINKER, 0);
header->bound = max_id_bound;
header->schema = 0u;
@@ -244,44 +262,55 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
linked_module->AddExtInstImport(
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
do {
const Instruction* memory_model_inst = input_modules[0]->GetMemoryModel();
if (memory_model_inst == nullptr) break;
const Instruction* linked_memory_model_inst =
input_modules.front()->GetMemoryModel();
if (linked_memory_model_inst == nullptr) {
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "Input module 1 is lacking an OpMemoryModel instruction.";
}
const uint32_t linked_addressing_model =
linked_memory_model_inst->GetSingleWordOperand(0u);
const uint32_t linked_memory_model =
linked_memory_model_inst->GetSingleWordOperand(1u);
uint32_t addressing_model = memory_model_inst->GetSingleWordOperand(0u);
uint32_t memory_model = memory_model_inst->GetSingleWordOperand(1u);
for (const auto& module : input_modules) {
memory_model_inst = module->GetMemoryModel();
if (memory_model_inst == nullptr) continue;
for (std::size_t i = 1; i < input_modules.size(); ++i) {
const Module* module = input_modules[i];
const Instruction* memory_model_inst = module->GetMemoryModel();
if (memory_model_inst == nullptr)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "Input module " << (i + 1)
<< " is lacking an OpMemoryModel instruction.";
if (addressing_model != memory_model_inst->GetSingleWordOperand(0u)) {
spv_operand_desc initial_desc = nullptr, current_desc = nullptr;
grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
addressing_model, &initial_desc);
grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
memory_model_inst->GetSingleWordOperand(0u),
&current_desc);
return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
<< "Conflicting addressing models: " << initial_desc->name
<< " vs " << current_desc->name << ".";
}
if (memory_model != memory_model_inst->GetSingleWordOperand(1u)) {
spv_operand_desc initial_desc = nullptr, current_desc = nullptr;
grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, memory_model,
&initial_desc);
grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL,
memory_model_inst->GetSingleWordOperand(1u),
&current_desc);
return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
<< "Conflicting memory models: " << initial_desc->name << " vs "
<< current_desc->name << ".";
}
const uint32_t module_addressing_model =
memory_model_inst->GetSingleWordOperand(0u);
if (module_addressing_model != linked_addressing_model) {
spv_operand_desc linked_desc = nullptr, module_desc = nullptr;
grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
linked_addressing_model, &linked_desc);
grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL,
module_addressing_model, &module_desc);
return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
<< "Conflicting addressing models: " << linked_desc->name
<< " (input modules 1 through " << i << ") vs "
<< module_desc->name << " (input module " << (i + 1) << ").";
}
if (memory_model_inst != nullptr)
linked_module->SetMemoryModel(std::unique_ptr<Instruction>(
memory_model_inst->Clone(linked_context)));
} while (false);
const uint32_t module_memory_model =
memory_model_inst->GetSingleWordOperand(1u);
if (module_memory_model != linked_memory_model) {
spv_operand_desc linked_desc = nullptr, module_desc = nullptr;
grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, linked_memory_model,
&linked_desc);
grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, module_memory_model,
&module_desc);
return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
<< "Conflicting memory models: " << linked_desc->name
<< " (input modules 1 through " << i << ") vs "
<< module_desc->name << " (input module " << (i + 1) << ").";
}
}
linked_module->SetMemoryModel(std::unique_ptr<Instruction>(
linked_memory_model_inst->Clone(linked_context)));
std::vector<std::pair<uint32_t, std::string>> entry_points;
for (const auto& module : input_modules)
@@ -332,7 +361,7 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
// If the generated module uses SPIR-V 1.1 or higher, add an
// OpModuleProcessed instruction about the linking step.
if (linked_module->version() >= 0x10100) {
if (linked_module->version() >= SPV_SPIRV_VERSION_WORD(1, 1)) {
const std::string processed_string("Linked by SPIR-V Tools Linker");
std::vector<uint32_t> processed_words =
spvtools::utils::MakeVector(processed_string);
@@ -349,18 +378,12 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
// TODO(pierremoreau): Since the modules have not been validate, should we
// expect SpvStorageClassFunction variables outside
// functions?
uint32_t num_global_values = 0u;
for (const auto& module : input_modules) {
for (const auto& inst : module->types_values()) {
linked_module->AddType(
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
num_global_values += inst.opcode() == SpvOpVariable;
}
}
if (num_global_values > 0xFFFF)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL)
<< "The limit of global values, 65535, was exceeded;"
<< " " << num_global_values << " global values were found.";
// Process functions and their basic blocks
for (const auto& module : input_modules) {
@@ -632,6 +655,34 @@ spv_result_t VerifyIds(const MessageConsumer& consumer,
return SPV_SUCCESS;
}
spv_result_t VerifyLimits(const MessageConsumer& consumer,
const opt::IRContext& linked_context) {
spv_position_t position = {};
const uint32_t max_id_bound = linked_context.module()->id_bound();
if (max_id_bound >= SPV_LIMIT_RESULT_ID_BOUND)
DiagnosticStream({0u, 0u, 4u}, consumer, "", SPV_WARNING)
<< "The minimum limit of IDs, " << (SPV_LIMIT_RESULT_ID_BOUND - 1)
<< ", was exceeded:"
<< " " << max_id_bound << " is the current ID bound.\n"
<< "The resulting module might not be supported by all "
"implementations.";
size_t num_global_values = 0u;
for (const auto& inst : linked_context.module()->types_values()) {
num_global_values += inst.opcode() == SpvOpVariable;
}
if (num_global_values >= SPV_LIMIT_GLOBAL_VARIABLES_MAX)
DiagnosticStream(position, consumer, "", SPV_WARNING)
<< "The minimum limit of global values, "
<< (SPV_LIMIT_GLOBAL_VARIABLES_MAX - 1) << ", was exceeded;"
<< " " << num_global_values << " global values were found.\n"
<< "The resulting module might not be supported by all "
"implementations.";
return SPV_SUCCESS;
}
} // namespace
spv_result_t Link(const Context& context,
@@ -756,7 +807,11 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries,
pass_res = manager.Run(&linked_context);
if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
// Phase 11: Output the module
// Phase 11: Warn if SPIR-V limits were exceeded
res = VerifyLimits(consumer, linked_context);
if (res != SPV_SUCCESS) return res;
// Phase 12: Output the module
linked_context.module()->ToBinary(linked_binary, true);
return SPV_SUCCESS;

View File

@@ -40,12 +40,12 @@ struct OpcodeDescPtrLen {
static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries),
kOpcodeTableEntries};
// Represents a vendor tool entry in the SPIR-V XML Regsitry.
// Represents a vendor tool entry in the SPIR-V XML Registry.
struct VendorTool {
uint32_t value;
const char* vendor;
const char* tool; // Might be empty string.
const char* vendor_tool; // Combiantion of vendor and tool.
const char* vendor_tool; // Combination of vendor and tool.
};
const VendorTool vendor_tools[] = {

View File

@@ -23,7 +23,7 @@ namespace spvtools {
namespace opt {
// Replaces the extensions VK_AMD_shader_ballot, VK_AMD_gcn_shader, and
// VK_AMD_shader_trinary_minmax with equivalant code using core instructions and
// VK_AMD_shader_trinary_minmax with equivalent code using core instructions and
// capabilities.
class AmdExtensionToKhrPass : public Pass {
public:

View File

@@ -83,7 +83,7 @@ class BasicBlock {
const Instruction* GetMergeInst() const;
Instruction* GetMergeInst();
// Returns the OpLoopMerge instruciton in this basic block, if it exists.
// Returns the OpLoopMerge instruction in this basic block, if it exists.
// Otherwise return null. May be used whenever tail() can be used.
const Instruction* GetLoopMergeInst() const;
Instruction* GetLoopMergeInst();

View File

@@ -30,7 +30,7 @@ class CFG {
public:
explicit CFG(Module* module);
// Return the list of predecesors for basic block with label |blkid|.
// Return the list of predecessors for basic block with label |blkid|.
// TODO(dnovillo): Move this to BasicBlock.
const std::vector<uint32_t>& preds(uint32_t blk_id) const {
assert(label2preds_.count(blk_id));

View File

@@ -550,7 +550,7 @@ ConstantFoldingRule FoldFAdd() { return FoldFPBinaryOp(FOLD_FPARITH_OP(+)); }
ConstantFoldingRule FoldFMul() { return FoldFPBinaryOp(FOLD_FPARITH_OP(*)); }
// Returns the constant that results from evaluating |numerator| / 0.0. Returns
// |nullptr| if the result could not be evalutated.
// |nullptr| if the result could not be evaluated.
const analysis::Constant* FoldFPScalarDivideByZero(
const analysis::Type* result_type, const analysis::Constant* numerator,
analysis::ConstantManager* const_mgr) {
@@ -1346,7 +1346,7 @@ void ConstantFoldingRules::AddFoldingRules() {
FoldFPUnaryOp(FoldFTranscendentalUnary(std::log)));
#ifdef __ANDROID__
// Android NDK r15c tageting ABI 15 doesn't have full support for C++11
// Android NDK r15c targeting ABI 15 doesn't have full support for C++11
// (no std::exp2/log2). ::exp2 is available from C99 but ::log2 isn't
// available up until ABI 18 so we use a shim
auto log2_shim = [](double v) -> double { return log(v) / log(2.0); };

View File

@@ -541,7 +541,7 @@ class ConstantManager {
// instruction at the end of the current module's types section.
//
// |type_id| is an optional argument for disambiguating equivalent types. If
// |type_id| is specified, the contant returned will have that type id.
// |type_id| is specified, the constant returned will have that type id.
Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0,
Module::inst_iterator* pos = nullptr);

View File

@@ -181,7 +181,7 @@ bool ConvertToHalfPass::ProcessPhi(Instruction* inst, uint32_t from_width,
uint32_t to_width) {
// Add converts of any float operands to to_width if they are of from_width.
// If converting to 16, change type of phi to float16 equivalent and remember
// result id. Converts need to be added to preceeding blocks.
// result id. Converts need to be added to preceding blocks.
uint32_t ocnt = 0;
uint32_t* prev_idp;
bool modified = false;

View File

@@ -158,7 +158,7 @@ class DeadBranchElimPass : public MemPass {
uint32_t cont_id, uint32_t header_id, uint32_t merge_id,
std::unordered_set<BasicBlock*>* blocks_with_back_edges);
// Returns true if there is a brach to the merge node of the selection
// Returns true if there is a branch to the merge node of the selection
// construct |switch_header_id| that is inside a nested selection construct or
// in the header of the nested selection construct.
bool SwitchHasNestedBreak(uint32_t switch_header_id);

View File

@@ -149,7 +149,7 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
// Create new constant directly into global value area, bypassing the
// Constant manager. This is used when the DefUse or Constant managers
// are invalid and cannot be regenerated due to the module being in an
// inconsistant state e.g. in the middle of significant modification
// inconsistent state e.g. in the middle of significant modification
// such as inlining. Invalidate Constant and DefUse managers if used.
uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) {
uint32_t id = context->TakeNextId();

View File

@@ -190,7 +190,7 @@ class DefUseManager {
// Returns the annotation instrunctions which are a direct use of the given
// |id|. This means when the decorations are applied through decoration
// group(s), this function will just return the OpGroupDecorate
// instrcution(s) which refer to the given id as an operand. The OpDecorate
// instruction(s) which refer to the given id as an operand. The OpDecorate
// instructions which decorate the decoration group will not be returned.
std::vector<Instruction*> GetAnnotations(uint32_t id) const;
@@ -210,7 +210,7 @@ class DefUseManager {
friend bool CompareAndPrintDifferences(const DefUseManager&,
const DefUseManager&);
// If |inst| has not already been analysed, then analyses its defintion and
// If |inst| has not already been analysed, then analyses its definition and
// uses.
void UpdateDefUse(Instruction* inst);

View File

@@ -118,7 +118,7 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var,
if (use->NumInOperands() == 2) {
// We are not indexing into the replacement variable. We can replaces the
// access chain with the replacement varibale itself.
// access chain with the replacement variable itself.
context()->ReplaceAllUsesWith(use->result_id(), replacement_var);
context()->KillInst(use);
return true;
@@ -135,8 +135,8 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var,
// Use the replacement variable as the base address.
new_operands.push_back({SPV_OPERAND_TYPE_ID, {replacement_var}});
// Drop the first index because it is consumed by the replacment, and copy the
// rest.
// Drop the first index because it is consumed by the replacement, and copy
// the rest.
for (uint32_t i = 4; i < use->NumOperands(); i++) {
new_operands.emplace_back(use->GetOperand(i));
}

View File

@@ -48,7 +48,7 @@ namespace {
// BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
// SuccessorLambda - Lamdba matching the signature of 'const
// std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
// succeding BasicBlock A.
// succeeding BasicBlock A.
// PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
// called on each node traversed AFTER their children.
// PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be
@@ -69,7 +69,7 @@ static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
// BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
// SuccessorLambda - Lamdba matching the signature of 'const
// std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
// succeding BasicBlock A.
// succeeding BasicBlock A.
// PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
// called on each node traversed after their children.
template <typename BBType, typename SuccessorLambda, typename PostLambda>

View File

@@ -38,7 +38,7 @@ Pass::Status EliminateDeadMembersPass::Process() {
}
void EliminateDeadMembersPass::FindLiveMembers() {
// Until we have implemented the rewritting of OpSpecConsantOp instructions,
// Until we have implemented the rewriting of OpSpecConsantOp instructions,
// we have to mark them as fully used just to be safe.
for (auto& inst : get_module()->types_values()) {
if (inst.opcode() == SpvOpSpecConstantOp) {
@@ -570,7 +570,7 @@ bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeStruct:
// The type will have already been rewriten, so use the new member
// The type will have already been rewritten, so use the new member
// index.
type_id = type_inst->GetSingleWordInOperand(new_member_idx);
break;

View File

@@ -540,7 +540,7 @@ std::vector<uint32_t> InstructionFolder::FoldVectors(
// in 32-bit words here. The reason of not using FoldScalars() here
// is that we do not create temporary null constants as components
// when the vector operand is a NullConstant because Constant creation
// may need extra checks for the validity and that is not manageed in
// may need extra checks for the validity and that is not managed in
// here.
if (const analysis::ScalarConstant* scalar_component =
vector_operand->GetComponents().at(d)->AsScalarConstant()) {

View File

@@ -115,7 +115,7 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp(
Instruction* folded_inst = nullptr;
assert(inst->GetInOperand(0).type ==
SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER &&
"The first in-operand of OpSpecContantOp instruction must be of "
"The first in-operand of OpSpecConstantOp instruction must be of "
"SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type");
switch (static_cast<SpvOp>(inst->GetSingleWordInOperand(0))) {

View File

@@ -13,7 +13,7 @@
// limitations under the License.
// This pass injects code in a graphics shader to implement guarantees
// satisfying Vulkan's robustBufferAcces rules. Robust access rules permit
// satisfying Vulkan's robustBufferAccess rules. Robust access rules permit
// an out-of-bounds access to be redirected to an access of the same type
// (load, store, etc.) but within the same root object.
//
@@ -74,7 +74,7 @@
// Pointers are always (correctly) typed and so the address and number of
// consecutive locations are fully determined by the pointer.
//
// - A pointer value orginates as one of few cases:
// - A pointer value originates as one of few cases:
//
// - OpVariable for an interface object or an array of them: image,
// buffer (UBO or SSBO), sampler, sampled-image, push-constant, input
@@ -958,7 +958,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
constant_mgr->GetDefiningInstruction(component_0)->result_id();
// If the image is a cube array, then the last component of the queried
// size is the layer count. In the query, we have to accomodate folding
// size is the layer count. In the query, we have to accommodate folding
// in the face index ranging from 0 through 5. The inclusive upper bound
// on the third coordinate therefore is multiplied by 6.
auto* query_size_including_faces = query_size;

View File

@@ -111,7 +111,7 @@ class GraphicsRobustAccessPass : public Pass {
Instruction* max, Instruction* where);
// Returns a new instruction which evaluates to the length the runtime array
// referenced by the access chain at the specfied index. The instruction is
// referenced by the access chain at the specified index. The instruction is
// inserted before the access chain instruction. Returns a null pointer in
// some cases if assumptions are violated (rather than asserting out).
opt::Instruction* MakeRuntimeArrayLengthInst(Instruction* access_chain,

View File

@@ -147,11 +147,11 @@ class InstBindlessCheckPass : public InstrumentPass {
uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder);
// Clone original image computation starting at |image_id| into |builder|.
// This may generate more than one instruction if neccessary.
// This may generate more than one instruction if necessary.
uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
// Clone original original reference encapsulated by |ref| into |builder|.
// This may generate more than one instruction if neccessary.
// This may generate more than one instruction if necessary.
uint32_t CloneOriginalReference(RefAnalysis* ref,
InstructionBuilder* builder);

View File

@@ -122,7 +122,7 @@ inline bool operator!=(const Operand& o1, const Operand& o2) {
}
// This structure is used to represent a DebugScope instruction from
// the OpenCL.100.DebugInfo extened instruction set. Note that we can
// the OpenCL.100.DebugInfo extended instruction set. Note that we can
// ignore the result id of DebugScope instruction because it is not
// used for anything. We do not keep it to reduce the size of
// structure.

View File

@@ -50,7 +50,7 @@
// A validation pass may read or write multiple buffers. All such buffers
// are located in a single debug descriptor set whose index is passed at the
// creation of the instrumentation pass. The bindings of the buffers used by
// a validation pass are permanantly assigned and fixed and documented by
// a validation pass are permanently assigned and fixed and documented by
// the kDebugOutput* static consts.
namespace spvtools {
@@ -179,8 +179,8 @@ class InstrumentPass : public Pass {
// the error. Every stage will write a fixed number of words. Vertex shaders
// will write the Vertex and Instance ID. Fragment shaders will write
// FragCoord.xy. Compute shaders will write the GlobalInvocation ID.
// The tesselation eval shader will write the Primitive ID and TessCoords.uv.
// The tesselation control shader and geometry shader will write the
// The tessellation eval shader will write the Primitive ID and TessCoords.uv.
// The tessellation control shader and geometry shader will write the
// Primitive ID and Invocation ID.
//
// The Validation Error Code specifies the exact error which has occurred.

View File

@@ -106,7 +106,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
analyses_to_invalidate |= kAnalysisDebugInfo;
}
// The dominator analysis hold the psuedo entry and exit nodes from the CFG.
// The dominator analysis hold the pseudo entry and exit nodes from the CFG.
// Also if the CFG change the dominators many changed as well, so the
// dominator analysis should be invalidated as well.
if (analyses_to_invalidate & kAnalysisCFG) {

View File

@@ -302,7 +302,7 @@ class IRContext {
}
}
// Returns a pointer the decoration manager. If the decoration manger is
// Returns a pointer the decoration manager. If the decoration manager is
// invalid, it is rebuilt first.
analysis::DecorationManager* get_decoration_mgr() {
if (!AreAnalysesValid(kAnalysisDecorations)) {
@@ -385,7 +385,7 @@ class IRContext {
// Deletes the instruction defining the given |id|. Returns true on
// success, false if the given |id| is not defined at all. This method also
// erases the name, decorations, and defintion of |id|.
// erases the name, decorations, and definition of |id|.
//
// Pointers and iterators pointing to the deleted instructions become invalid.
// However other pointers and iterators are still valid.
@@ -802,7 +802,7 @@ class IRContext {
// iterators to traverse instructions.
std::unordered_map<uint32_t, Function*> id_to_func_;
// A bitset indicating which analyes are currently valid.
// A bitset indicating which analyzes are currently valid.
Analysis valid_analyses_;
// Opcodes of shader capability core executable instructions

View File

@@ -81,7 +81,7 @@ class LocalAccessChainConvertPass : public MemPass {
std::vector<Operand>* in_opnds);
// Create a load/insert/store equivalent to a store of
// |valId| through (constant index) access chaing |ptrInst|.
// |valId| through (constant index) access chain |ptrInst|.
// Append to |newInsts|. Returns true if successful.
bool GenAccessChainStoreReplacement(
const Instruction* ptrInst, uint32_t valId,

View File

@@ -719,7 +719,7 @@ bool Loop::FindNumberOfIterations(const Instruction* induction,
step_value = -step_value;
}
// Find the inital value of the loop and make sure it is a constant integer.
// Find the initial value of the loop and make sure it is a constant integer.
int64_t init_value = 0;
if (!GetInductionInitValue(induction, &init_value)) return false;
@@ -751,7 +751,7 @@ bool Loop::FindNumberOfIterations(const Instruction* induction,
// We retrieve the number of iterations using the following formula, diff /
// |step_value| where diff is calculated differently according to the
// |condition| and uses the |condition_value| and |init_value|. If diff /
// |step_value| is NOT cleanly divisable then we add one to the sum.
// |step_value| is NOT cleanly divisible then we add one to the sum.
int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value,
int64_t init_value, int64_t step_value) const {
int64_t diff = 0;
@@ -795,7 +795,7 @@ int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value,
// If the condition is not met to begin with the loop will never iterate.
if (!(init_value >= condition_value)) return 0;
// We subract one to make it the same as SpvOpGreaterThan as it is
// We subtract one to make it the same as SpvOpGreaterThan as it is
// functionally equivalent.
diff = init_value - (condition_value - 1);

View File

@@ -395,7 +395,7 @@ class Loop {
// Sets |merge| as the loop merge block. No checks are performed here.
inline void SetMergeBlockImpl(BasicBlock* merge) { loop_merge_ = merge; }
// Each differnt loop |condition| affects how we calculate the number of
// Each different loop |condition| affects how we calculate the number of
// iterations using the |condition_value|, |init_value|, and |step_values| of
// the induction variable. This method will return the number of iterations in
// a loop with those values for a given |condition|.

View File

@@ -29,7 +29,7 @@
// 2 - For each loop in the list, group each instruction into a set of related
// instructions by traversing each instructions users and operands recursively.
// We stop if we encounter an instruction we have seen before or an instruction
// which we don't consider relevent (i.e OpLoopMerge). We then group these
// which we don't consider relevant (i.e OpLoopMerge). We then group these
// groups into two different sets, one for the first loop and one for the
// second.
//

View File

@@ -33,7 +33,7 @@ namespace opt {
class LoopFissionPass : public Pass {
public:
// Fuction used to determine if a given loop should be split. Takes register
// Function used to determine if a given loop should be split. Takes register
// pressure region for that loop as a parameter and returns true if the loop
// should be split.
using FissionCriteriaFunction =

View File

@@ -165,7 +165,7 @@ bool LoopFusion::AreCompatible() {
// Check adjacency, |loop_0_| should come just before |loop_1_|.
// There is always at least one block between loops, even if it's empty.
// We'll check at most 2 preceeding blocks.
// We'll check at most 2 preceding blocks.
auto pre_header_1 = loop_1_->GetPreHeaderBlock();
@@ -712,7 +712,7 @@ void LoopFusion::Fuse() {
ld->RemoveLoop(loop_1_);
// Kill unnessecary instructions and remove all empty blocks.
// Kill unnecessary instructions and remove all empty blocks.
for (auto inst : instr_to_delete) {
context_->KillInst(inst);
}

View File

@@ -40,7 +40,7 @@ class LoopFusion {
// That means:
// * they both have one induction variable
// * they have the same upper and lower bounds
// - same inital value
// - same initial value
// - same condition
// * they have the same update step
// * they are adjacent, with |loop_0| appearing before |loop_1|

View File

@@ -33,7 +33,7 @@ class LoopFusionPass : public Pass {
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
// succesful to indicate whether changes have been made to the modue.
// successful to indicate whether changes have been made to the module.
Status Process() override;
private:

View File

@@ -261,7 +261,7 @@ class LoopPeelingPass : public Pass {
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
// succesful to indicate whether changes have been made to the modue.
// successful to indicate whether changes have been made to the module.
Pass::Status Process() override;
private:

View File

@@ -163,7 +163,7 @@ struct LoopUnrollState {
};
// This class implements the actual unrolling. It uses a LoopUnrollState to
// maintain the state of the unrolling inbetween steps.
// maintain the state of the unrolling in between steps.
class LoopUnrollerUtilsImpl {
public:
using BasicBlockListTy = std::vector<std::unique_ptr<BasicBlock>>;
@@ -209,7 +209,7 @@ class LoopUnrollerUtilsImpl {
// Add all blocks_to_add_ to function_ at the |insert_point|.
void AddBlocksToFunction(const BasicBlock* insert_point);
// Duplicates the |old_loop|, cloning each body and remaping the ids without
// Duplicates the |old_loop|, cloning each body and remapping the ids without
// removing instructions or changing relative structure. Result will be stored
// in |new_loop|.
void DuplicateLoop(Loop* old_loop, Loop* new_loop);
@@ -241,7 +241,7 @@ class LoopUnrollerUtilsImpl {
// Remap all the in |basic_block| to new IDs and keep the mapping of new ids
// to old
// ids. |loop| is used to identify special loop blocks (header, continue,
// ect).
// etc).
void AssignNewResultIds(BasicBlock* basic_block);
// Using the map built by AssignNewResultIds, replace the uses in |inst|
@@ -320,7 +320,7 @@ class LoopUnrollerUtilsImpl {
// and then be remapped at the end.
std::vector<Instruction*> loop_phi_instructions_;
// The number of loop iterations that the loop would preform pre-unroll.
// The number of loop iterations that the loop would perform pre-unroll.
size_t number_of_loop_iterations_;
// The amount that the loop steps each iteration.
@@ -839,7 +839,7 @@ void LoopUnrollerUtilsImpl::DuplicateLoop(Loop* old_loop, Loop* new_loop) {
new_loop->SetMergeBlock(new_merge);
}
// Whenever the utility copies a block it stores it in a tempory buffer, this
// Whenever the utility copies a block it stores it in a temporary buffer, this
// function adds the buffer into the Function. The blocks will be inserted
// after the block |insert_point|.
void LoopUnrollerUtilsImpl::AddBlocksToFunction(

View File

@@ -118,7 +118,7 @@ class LoopUnswitch {
// Find a value that can be used to select the default path.
// If none are possible, then it will just use 0. The value does not matter
// because this path will never be taken becaues the new switch outside of
// because this path will never be taken because the new switch outside of
// the loop cannot select this path either.
std::vector<uint32_t> existing_values;
for (uint32_t i = 2; i < switch_inst->NumInOperands(); i += 2) {

View File

@@ -30,7 +30,7 @@ class LoopUnswitchPass : public Pass {
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
// succesful to indicate whether changes have been made to the modue.
// successful to indicate whether changes have been made to the module.
Pass::Status Process() override;
private:

View File

@@ -123,7 +123,7 @@ class LoopUtils {
// Clone the |loop_| and make the new loop branch to the second loop on exit.
Loop* CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result);
// Perfom a partial unroll of |loop| by given |factor|. This will copy the
// Perform a partial unroll of |loop| by given |factor|. This will copy the
// body of the loop |factor| times. So a |factor| of one would give a new loop
// with the original body plus one unrolled copy body.
bool PartiallyUnroll(size_t factor);
@@ -139,7 +139,7 @@ class LoopUtils {
// 1. That the loop is in structured order.
// 2. That the continue block is a branch to the header.
// 3. That the only phi used in the loop is the induction variable.
// TODO(stephen@codeplay.com): This is a temporary mesure, after the loop is
// TODO(stephen@codeplay.com): This is a temporary measure, after the loop is
// converted into LCSAA form and has a single entry and exit we can rewrite
// the other phis.
// 4. That this is an inner most loop, or that loops contained within this

View File

@@ -247,7 +247,7 @@ class MergeReturnPass : public MemPass {
// Add new phi nodes for any id that no longer dominate all of it uses. A phi
// node is added to a block |bb| for an id if the id is defined between the
// original immediate dominator of |bb| and its new immidiate dominator. It
// original immediate dominator of |bb| and its new immediate dominator. It
// is assumed that at this point there are no unreachable blocks in the
// control flow graph.
void AddNewPhiNodes();
@@ -273,7 +273,7 @@ class MergeReturnPass : public MemPass {
void InsertAfterElement(BasicBlock* element, BasicBlock* new_element,
std::list<BasicBlock*>* list);
// Creates a single case switch around all of the exectuable code of the
// Creates a single case switch around all of the executable code of the
// current function where the switch and case value are both zero and the
// default is the merge block. Returns after the switch is executed. Sets
// |final_return_block_|.

View File

@@ -324,6 +324,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
RegisterPass(CreateLocalAccessChainConvertPass());
} else if (pass_name == "replace-desc-array-access-using-var-index") {
RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
} else if (pass_name == "spread-volatile-semantics") {
RegisterPass(CreateSpreadVolatileSemanticsPass());
} else if (pass_name == "descriptor-scalar-replacement") {
RegisterPass(CreateDescriptorScalarReplacementPass());
} else if (pass_name == "eliminate-dead-code-aggressive") {
@@ -976,6 +978,11 @@ Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
}
Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::SpreadVolatileSemantics>());
}
Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::DescriptorScalarReplacement>());

View File

@@ -129,7 +129,7 @@ class Pass {
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
// succesful to indicate whether changes are made to the module.
// successful to indicate whether changes are made to the module.
virtual Status Process() = 0;
// Return the next available SSA id and increment it.

View File

@@ -54,7 +54,7 @@ class PassManager {
// Adds an externally constructed pass.
void AddPass(std::unique_ptr<Pass> pass);
// Uses the argument |args| to construct a pass instance of type |T|, and adds
// the pass instance to this pass manger. The pass added will use this pass
// the pass instance to this pass manager. The pass added will use this pass
// manager's message consumer.
template <typename T, typename... Args>
void AddPass(Args&&... args);
@@ -70,7 +70,7 @@ class PassManager {
// Runs all passes on the given |module|. Returns Status::Failure if errors
// occur when processing using one of the registered passes. All passes
// registered after the error-reporting pass will be skipped. Returns the
// corresponding Status::Success if processing is succesful to indicate
// corresponding Status::Success if processing is successful to indicate
// whether changes are made to the module.
//
// After running all the passes, they are removed from the list.

View File

@@ -71,6 +71,7 @@
#include "source/opt/scalar_replacement_pass.h"
#include "source/opt/set_spec_constant_default_value_pass.h"
#include "source/opt/simplification_pass.h"
#include "source/opt/spread_volatile_semantics.h"
#include "source/opt/ssa_rewrite_pass.h"
#include "source/opt/strength_reduction_pass.h"
#include "source/opt/strip_debug_info_pass.h"

View File

@@ -44,7 +44,7 @@ class PrivateToLocalPass : public Pass {
// class of |function|. Returns false if the variable could not be moved.
bool MoveVariable(Instruction* variable, Function* function);
// |inst| is an instruction declaring a varible. If that variable is
// |inst| is an instruction declaring a variable. If that variable is
// referenced in a single function and all of uses are valid as defined by
// |IsValidUse|, then that function is returned. Otherwise, the return
// value is |nullptr|.

View File

@@ -41,7 +41,7 @@ class RedundancyEliminationPass : public LocalRedundancyEliminationPass {
// in the function containing |bb|.
//
// |value_to_ids| is a map from value number to ids. If {vn, id} is in
// |value_to_ids| then vn is the value number of id, and the defintion of id
// |value_to_ids| then vn is the value number of id, and the definition of id
// dominates |bb|.
//
// Returns true if at least one instruction is deleted.

View File

@@ -47,7 +47,7 @@ class ReplaceDescArrayAccessUsingVarIndex : public Pass {
}
private:
// Replaces all acceses to |var| using variable indices with constant
// Replaces all accesses to |var| using variable indices with constant
// elements of the array |var|. Creates switch-case statements to determine
// the value of the variable index for all the possible cases. Returns
// whether replacement is done or not.
@@ -170,7 +170,7 @@ class ReplaceDescArrayAccessUsingVarIndex : public Pass {
// Creates and adds an OpSwitch used for the selection of OpAccessChain whose
// first Indexes operand is |access_chain_index_var_id|. The OpSwitch will be
// added at the end of |parent_block|. It will jump to |default_id| for the
// default case and jumps to one of case blocks whoes ids are |case_block_ids|
// default case and jumps to one of case blocks whose ids are |case_block_ids|
// if |access_chain_index_var_id| matches the case number. |merge_id| is the
// merge block id.
void AddSwitchForAccessChain(

View File

@@ -581,7 +581,7 @@ static void PushToString(T id, std::u32string* str) {
// Implements the hashing of SENodes.
size_t SENodeHash::operator()(const SENode* node) const {
// Concatinate the terms into a string which we can hash.
// Concatenate the terms into a string which we can hash.
std::u32string hash_string{};
// Hashing the type as a string is safer than hashing the enum as the enum is

View File

@@ -167,7 +167,7 @@ class SENode {
const ChildContainerType& GetChildren() const { return children_; }
ChildContainerType& GetChildren() { return children_; }
// Return true if this node is a cant compute node.
// Return true if this node is a can't compute node.
bool IsCantCompute() const { return GetType() == CanNotCompute; }
// Implements a casting method for each type.

View File

@@ -88,7 +88,7 @@ class SENodeSimplifyImpl {
private:
// Recursively descend through the graph to build up the accumulator objects
// which are used to flatten the graph. |child| is the node currenty being
// which are used to flatten the graph. |child| is the node currently being
// traversed and the |negation| flag is used to signify that this operation
// was preceded by a unary negative operation and as such the result should be
// negated.

View File

@@ -0,0 +1,314 @@
// Copyright (c) 2022 Google LLC
//
// 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 "source/opt/spread_volatile_semantics.h"
#include "source/opt/decoration_manager.h"
#include "source/opt/ir_builder.h"
#include "source/spirv_constant.h"
namespace spvtools {
namespace opt {
namespace {
const uint32_t kOpDecorateInOperandBuiltinDecoration = 2u;
const uint32_t kOpLoadInOperandMemoryOperands = 1u;
const uint32_t kOpEntryPointInOperandEntryPoint = 1u;
const uint32_t kOpEntryPointInOperandInterface = 3u;
bool HasBuiltinDecoration(analysis::DecorationManager* decoration_manager,
uint32_t var_id, uint32_t built_in) {
return decoration_manager->FindDecoration(
var_id, SpvDecorationBuiltIn, [built_in](const Instruction& inst) {
return built_in == inst.GetSingleWordInOperand(
kOpDecorateInOperandBuiltinDecoration);
});
}
bool IsBuiltInForRayTracingVolatileSemantics(uint32_t built_in) {
switch (built_in) {
case SpvBuiltInSMIDNV:
case SpvBuiltInWarpIDNV:
case SpvBuiltInSubgroupSize:
case SpvBuiltInSubgroupLocalInvocationId:
case SpvBuiltInSubgroupEqMask:
case SpvBuiltInSubgroupGeMask:
case SpvBuiltInSubgroupGtMask:
case SpvBuiltInSubgroupLeMask:
case SpvBuiltInSubgroupLtMask:
return true;
default:
return false;
}
}
bool HasBuiltinForRayTracingVolatileSemantics(
analysis::DecorationManager* decoration_manager, uint32_t var_id) {
return decoration_manager->FindDecoration(
var_id, SpvDecorationBuiltIn, [](const Instruction& inst) {
uint32_t built_in =
inst.GetSingleWordInOperand(kOpDecorateInOperandBuiltinDecoration);
return IsBuiltInForRayTracingVolatileSemantics(built_in);
});
}
bool HasVolatileDecoration(analysis::DecorationManager* decoration_manager,
uint32_t var_id) {
return decoration_manager->HasDecoration(var_id, SpvDecorationVolatile);
}
bool HasOnlyEntryPointsAsFunctions(IRContext* context, Module* module) {
std::unordered_set<uint32_t> entry_function_ids;
for (Instruction& entry_point : module->entry_points()) {
entry_function_ids.insert(
entry_point.GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint));
}
for (auto& function : *module) {
if (entry_function_ids.find(function.result_id()) ==
entry_function_ids.end()) {
std::string message(
"Functions of SPIR-V for spread-volatile-semantics pass input must "
"be inlined except entry points");
message += "\n " + function.DefInst().PrettyPrint(
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
context->consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str());
return false;
}
}
return true;
}
} // namespace
Pass::Status SpreadVolatileSemantics::Process() {
if (!HasOnlyEntryPointsAsFunctions(context(), get_module())) {
return Status::Failure;
}
const bool is_vk_memory_model_enabled =
context()->get_feature_mgr()->HasCapability(
SpvCapabilityVulkanMemoryModel);
CollectTargetsForVolatileSemantics(is_vk_memory_model_enabled);
// If VulkanMemoryModel capability is not enabled, we have to set Volatile
// decoration for interface variables instead of setting Volatile for load
// instructions. If an interface (or pointers to it) is used by two load
// instructions in two entry points and one must be volatile while another
// is not, we have to report an error for the conflict.
if (!is_vk_memory_model_enabled &&
HasInterfaceInConflictOfVolatileSemantics()) {
return Status::Failure;
}
return SpreadVolatileSemanticsToVariables(is_vk_memory_model_enabled);
}
Pass::Status SpreadVolatileSemantics::SpreadVolatileSemanticsToVariables(
const bool is_vk_memory_model_enabled) {
Status status = Status::SuccessWithoutChange;
for (Instruction& var : context()->types_values()) {
auto entry_function_ids =
EntryFunctionsToSpreadVolatileSemanticsForVar(var.result_id());
if (entry_function_ids.empty()) {
continue;
}
if (is_vk_memory_model_enabled) {
SetVolatileForLoadsInEntries(&var, entry_function_ids);
} else {
DecorateVarWithVolatile(&var);
}
status = Status::SuccessWithChange;
}
return status;
}
bool SpreadVolatileSemantics::IsTargetUsedByNonVolatileLoadInEntryPoint(
uint32_t var_id, Instruction* entry_point) {
uint32_t entry_function_id =
entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
return !VisitLoadsOfPointersToVariableInEntries(
var_id,
[](Instruction* load) {
// If it has a load without volatile memory operand, finish traversal
// and return false.
if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
return false;
}
uint32_t memory_operands =
load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
return (memory_operands & SpvMemoryAccessVolatileMask) != 0;
},
{entry_function_id});
}
bool SpreadVolatileSemantics::HasInterfaceInConflictOfVolatileSemantics() {
for (Instruction& entry_point : get_module()->entry_points()) {
SpvExecutionModel execution_model =
static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
for (uint32_t operand_index = kOpEntryPointInOperandInterface;
operand_index < entry_point.NumInOperands(); ++operand_index) {
uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
if (!EntryFunctionsToSpreadVolatileSemanticsForVar(var_id).empty() &&
!IsTargetForVolatileSemantics(var_id, execution_model) &&
IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
Instruction* inst = context()->get_def_use_mgr()->GetDef(var_id);
context()->EmitErrorMessage(
"Variable is a target for Volatile semantics for an entry point, "
"but it is not for another entry point",
inst);
return true;
}
}
}
return false;
}
void SpreadVolatileSemantics::MarkVolatileSemanticsForVariable(
uint32_t var_id, Instruction* entry_point) {
uint32_t entry_function_id =
entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint);
auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) {
var_ids_to_entry_fn_for_volatile_semantics_[var_id] = {entry_function_id};
return;
}
itr->second.insert(entry_function_id);
}
void SpreadVolatileSemantics::CollectTargetsForVolatileSemantics(
const bool is_vk_memory_model_enabled) {
for (Instruction& entry_point : get_module()->entry_points()) {
SpvExecutionModel execution_model =
static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
for (uint32_t operand_index = kOpEntryPointInOperandInterface;
operand_index < entry_point.NumInOperands(); ++operand_index) {
uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index);
if (!IsTargetForVolatileSemantics(var_id, execution_model)) {
continue;
}
if (is_vk_memory_model_enabled ||
IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) {
MarkVolatileSemanticsForVariable(var_id, &entry_point);
}
}
}
}
void SpreadVolatileSemantics::DecorateVarWithVolatile(Instruction* var) {
analysis::DecorationManager* decoration_manager =
context()->get_decoration_mgr();
uint32_t var_id = var->result_id();
if (HasVolatileDecoration(decoration_manager, var_id)) {
return;
}
get_decoration_mgr()->AddDecoration(
SpvOpDecorate, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {var_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
{SpvDecorationVolatile}}});
}
bool SpreadVolatileSemantics::VisitLoadsOfPointersToVariableInEntries(
uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
const std::unordered_set<uint32_t>& entry_function_ids) {
std::vector<uint32_t> worklist({var_id});
auto* def_use_mgr = context()->get_def_use_mgr();
while (!worklist.empty()) {
uint32_t ptr_id = worklist.back();
worklist.pop_back();
bool finish_traversal = !def_use_mgr->WhileEachUser(
ptr_id, [this, &worklist, &ptr_id, handle_load,
&entry_function_ids](Instruction* user) {
BasicBlock* block = context()->get_instr_block(user);
if (block == nullptr ||
entry_function_ids.find(block->GetParent()->result_id()) ==
entry_function_ids.end()) {
return true;
}
if (user->opcode() == SpvOpAccessChain ||
user->opcode() == SpvOpInBoundsAccessChain ||
user->opcode() == SpvOpPtrAccessChain ||
user->opcode() == SpvOpInBoundsPtrAccessChain ||
user->opcode() == SpvOpCopyObject) {
if (ptr_id == user->GetSingleWordInOperand(0))
worklist.push_back(user->result_id());
return true;
}
if (user->opcode() != SpvOpLoad) {
return true;
}
return handle_load(user);
});
if (finish_traversal) return false;
}
return true;
}
void SpreadVolatileSemantics::SetVolatileForLoadsInEntries(
Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids) {
// Set Volatile memory operand for all load instructions if they do not have
// it.
VisitLoadsOfPointersToVariableInEntries(
var->result_id(),
[](Instruction* load) {
if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) {
load->AddOperand(
{SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessVolatileMask}});
return true;
}
uint32_t memory_operands =
load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands);
memory_operands |= SpvMemoryAccessVolatileMask;
load->SetInOperand(kOpLoadInOperandMemoryOperands, {memory_operands});
return true;
},
entry_function_ids);
}
bool SpreadVolatileSemantics::IsTargetForVolatileSemantics(
uint32_t var_id, SpvExecutionModel execution_model) {
analysis::DecorationManager* decoration_manager =
context()->get_decoration_mgr();
if (execution_model == SpvExecutionModelFragment) {
return get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 6) &&
HasBuiltinDecoration(decoration_manager, var_id,
SpvBuiltInHelperInvocation);
}
if (execution_model == SpvExecutionModelIntersectionKHR ||
execution_model == SpvExecutionModelIntersectionNV) {
if (HasBuiltinDecoration(decoration_manager, var_id,
SpvBuiltInRayTmaxKHR)) {
return true;
}
}
switch (execution_model) {
case SpvExecutionModelRayGenerationKHR:
case SpvExecutionModelClosestHitKHR:
case SpvExecutionModelMissKHR:
case SpvExecutionModelCallableKHR:
case SpvExecutionModelIntersectionKHR:
return HasBuiltinForRayTracingVolatileSemantics(decoration_manager,
var_id);
default:
return false;
}
}
} // namespace opt
} // namespace spvtools

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2022 Google LLC
//
// 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.
#ifndef SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
#define SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class SpreadVolatileSemantics : public Pass {
public:
SpreadVolatileSemantics() {}
const char* name() const override { return "spread-volatile-semantics"; }
Status Process() override;
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations |
IRContext::kAnalysisInstrToBlockMapping;
}
private:
// Iterates interface variables and spreads the Volatile semantics if it has
// load instructions for the Volatile semantics.
Pass::Status SpreadVolatileSemanticsToVariables(
const bool is_vk_memory_model_enabled);
// Returns whether |var_id| is the result id of a target builtin variable for
// the volatile semantics for |execution_model| based on the Vulkan spec
// VUID-StandaloneSpirv-VulkanMemoryModel-04678 or
// VUID-StandaloneSpirv-VulkanMemoryModel-04679.
bool IsTargetForVolatileSemantics(uint32_t var_id,
SpvExecutionModel execution_model);
// Collects interface variables that need the volatile semantics.
// |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is
// enabled.
void CollectTargetsForVolatileSemantics(
const bool is_vk_memory_model_enabled);
// Reports an error if an interface variable is used by two entry points and
// it needs the Volatile decoration for one but not for another. Returns true
// if the error must be reported.
bool HasInterfaceInConflictOfVolatileSemantics();
// Returns whether the variable whose result is |var_id| is used by a
// non-volatile load or a pointer to it is used by a non-volatile load in
// |entry_point| or not.
bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id,
Instruction* entry_point);
// Visits load instructions of pointers to variable whose result id is
// |var_id| if the load instructions are in entry points whose
// function id is one of |entry_function_ids|. |handle_load| is a function to
// do some actions for the load instructions. Finishes the traversal and
// returns false if |handle_load| returns false for a load instruction.
// Otherwise, returns true after running |handle_load| for all the load
// instructions.
bool VisitLoadsOfPointersToVariableInEntries(
uint32_t var_id, const std::function<bool(Instruction*)>& handle_load,
const std::unordered_set<uint32_t>& entry_function_ids);
// Sets Memory Operands of OpLoad instructions that load |var| or pointers
// of |var| as Volatile if the function id of the OpLoad instruction is
// included in |entry_function_ids|.
void SetVolatileForLoadsInEntries(
Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids);
// Adds OpDecorate Volatile for |var| if it does not exist.
void DecorateVarWithVolatile(Instruction* var);
// Returns a set of entry function ids to spread the volatile semantics for
// the variable with the result id |var_id|.
std::unordered_set<uint32_t> EntryFunctionsToSpreadVolatileSemanticsForVar(
uint32_t var_id) {
auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id);
if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {};
return itr->second;
}
// Specifies that we have to spread the volatile semantics for the
// variable with the result id |var_id| for the entry point |entry_point|.
void MarkVolatileSemanticsForVariable(uint32_t var_id,
Instruction* entry_point);
// Result ids of variables to entry function ids for the volatile semantics
// spread.
std::unordered_map<uint32_t, std::unordered_set<uint32_t>>
var_ids_to_entry_fn_for_volatile_semantics_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_

View File

@@ -151,7 +151,7 @@ Pass::Status UnifyConstantPass::Process() {
// 'SpecId' decoration and all of them should be treated as unique.
// 'SpecId' is not applicable to SpecConstants defined with
// OpSpecConstant{Op|Composite}, their values are not necessary to be
// unique. When all the operands/compoents are the same between two
// unique. When all the operands/components are the same between two
// OpSpecConstant{Op|Composite} results, their result values must be the
// same so are unifiable.
case SpvOp::SpvOpSpecConstantOp:

View File

@@ -73,7 +73,7 @@ class VectorDCE : public MemPass {
bool RewriteInstructions(Function* function,
const LiveComponentMap& live_components);
// Makrs all DebugValue instructions that use |composite| for their values as
// Makes all DebugValue instructions that use |composite| for their values as
// dead instructions by putting them into |dead_dbg_value|.
void MarkDebugValueUsesAsDead(Instruction* composite,
std::vector<Instruction*>* dead_dbg_value);

View File

@@ -153,7 +153,7 @@ void RemoveStructMemberReductionOpportunity::AdjustAccessedIndices(
next_type = type_inst->GetSingleWordInOperand(0);
break;
case SpvOpTypeStruct: {
// Struct types are special becuase (a) we may need to adjust the index
// Struct types are special because (a) we may need to adjust the index
// being used, if the struct type is the one from which we are removing
// a member, and (b) the type encountered by following the current index
// is dependent on the value of the index.

View File

@@ -136,9 +136,9 @@ RemoveUnusedStructMemberReductionOpportunityFinder::GetAvailableOpportunities(
}
}
// We now know those struct indices that are unsed, and we make a reduction
// We now know those struct indices that are unused, and we make a reduction
// opportunity for each of them. By mapping each relevant member index to the
// structs in which it is unsed, we will group all opportunities to remove
// structs in which it is unused, we will group all opportunities to remove
// member k of a struct (for some k) together. This reduces the likelihood
// that opportunities to remove members from the same struct will be adjacent,
// which is good because such opportunities mutually disable one another.

View File

@@ -96,7 +96,7 @@ StructuredConstructToBlockReductionOpportunityFinder::GetAvailableOpportunities(
// This also means that we don't add a region.
continue;
}
// We have a reachable header block with a rechable merge that
// We have a reachable header block with a reachable merge that
// postdominates the header: this means we have a new region.
regions.emplace(&block, std::unordered_set<opt::BasicBlock*>());
}
@@ -128,7 +128,7 @@ bool StructuredConstructToBlockReductionOpportunityFinder::
if (!block->WhileEachInst(
[context, &header, &region](opt::Instruction* inst) -> bool {
if (inst->result_id() == 0) {
// The instruction does not genreate a result id, thus it cannot
// The instruction does not generate a result id, thus it cannot
// be referred to outside the region - this is fine.
return true;
}

View File

@@ -27,7 +27,7 @@ typedef struct spv_header_t {
uint32_t generator;
uint32_t bound;
uint32_t schema; // NOTE: Reserved
const uint32_t* instructions; // NOTE: Unfixed pointer to instruciton stream
const uint32_t* instructions; // NOTE: Unfixed pointer to instruction stream
} spv_header_t;
#endif // SOURCE_SPIRV_DEFINITION_H_

View File

@@ -31,7 +31,7 @@ uint64_t spvFixDoubleWord(const uint32_t low, const uint32_t high,
spv_result_t spvBinaryEndianness(const spv_const_binary binary,
spv_endianness_t* endian);
// Returns true if the given endianness matches the host's native endiannes.
// Returns true if the given endianness matches the host's native endianness.
bool spvIsHostEndian(spv_endianness_t endian);
#endif // SOURCE_SPIRV_ENDIAN_H_

View File

@@ -74,6 +74,8 @@ const char* spvTargetEnvDescription(spv_target_env env) {
return "SPIR-V 1.5 (under Vulkan 1.2 semantics)";
case SPV_ENV_UNIVERSAL_1_6:
return "SPIR-V 1.6";
case SPV_ENV_VULKAN_1_3:
return "SPIR-V 1.6 (under Vulkan 1.3 semantics)";
case SPV_ENV_MAX:
assert(false && "Invalid target environment value.");
break;
@@ -116,6 +118,7 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_2:
return SPV_SPIRV_VERSION_WORD(1, 5);
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
return SPV_SPIRV_VERSION_WORD(1, 6);
case SPV_ENV_MAX:
assert(false && "Invalid target environment value.");
@@ -129,6 +132,7 @@ static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
{"vulkan1.0", SPV_ENV_VULKAN_1_0},
{"vulkan1.1", SPV_ENV_VULKAN_1_1},
{"vulkan1.2", SPV_ENV_VULKAN_1_2},
{"vulkan1.3", SPV_ENV_VULKAN_1_3},
{"spv1.0", SPV_ENV_UNIVERSAL_1_0},
{"spv1.1", SPV_ENV_UNIVERSAL_1_1},
{"spv1.2", SPV_ENV_UNIVERSAL_1_2},
@@ -182,7 +186,8 @@ static const VulkanEnv ordered_vulkan_envs[] = {
{SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)},
{SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
{SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
{SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}};
{SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)},
{SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}};
bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
spv_target_env* env) {
@@ -222,6 +227,7 @@ bool spvIsVulkanEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_1:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_VULKAN_1_3:
return true;
case SPV_ENV_WEBGPU_0:
assert(false && "Deprecated target environment value.");
@@ -251,6 +257,7 @@ bool spvIsOpenCLEnv(spv_target_env env) {
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
return false;
case SPV_ENV_OPENCL_1_2:
case SPV_ENV_OPENCL_EMBEDDED_1_2:
@@ -292,6 +299,7 @@ bool spvIsOpenGLEnv(spv_target_env env) {
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
return false;
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
@@ -330,6 +338,7 @@ bool spvIsValidEnv(spv_target_env env) {
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
case SPV_ENV_OPENGL_4_2:
@@ -365,7 +374,8 @@ std::string spvLogStringForEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_1:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2: {
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_VULKAN_1_3: {
return "Vulkan";
}
case SPV_ENV_UNIVERSAL_1_0:

View File

@@ -40,7 +40,7 @@ std::string spvLogStringForEnv(spv_target_env env);
// Returns a formatted list of all SPIR-V target environment names that
// can be parsed by spvParseTargetEnv.
// |pad| is the number of space characters that the begining of each line
// |pad| is the number of space characters that the beginning of each line
// except the first one will be padded with.
// |wrap| is the max length of lines the user desires. Word-wrapping will
// occur to satisfy this limit.

View File

@@ -42,6 +42,7 @@ spv_context spvContextCreate(spv_target_env env) {
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
break;
default:
return nullptr;

View File

@@ -32,7 +32,7 @@ class BitVector {
enum { kInitialNumBits = 1024 };
public:
// Creates a bit vector contianing 0s.
// Creates a bit vector containing 0s.
BitVector(uint32_t reserved_size = kInitialNumBits)
: bits_((reserved_size - 1) / kBitContainerSize + 1, 0) {}

View File

@@ -59,7 +59,7 @@ class IntrusiveList {
// Moves the contents of the given list to the list being constructed.
IntrusiveList(IntrusiveList&&);
// Destorys the list. Note that the elements of the list will not be deleted,
// Destroys the list. Note that the elements of the list will not be deleted,
// but they will be removed from the list.
virtual ~IntrusiveList();

View File

@@ -220,7 +220,7 @@ EncodeNumberStatus ParseAndEncodeIntegerNumber(
std::function<void(uint32_t)> emit, std::string* error_msg);
// Parses a floating point value of a given |type| from the given |text| and
// encodes the number by the given |emit| funciton. On success, returns
// encodes the number by the given |emit| function. On success, returns
// EncodeNumberStatus::kSuccess and the parsed number will be consumed by the
// given |emit| function word by word (least significant word first). On
// failure, this function returns the error code of the encoding status and

View File

@@ -175,9 +175,12 @@ class SmallVector {
return true;
}
// Avoid infinite recursion from rewritten operators in C++20
#if __cplusplus <= 201703L
friend bool operator==(const std::vector<T>& lhs, const SmallVector& rhs) {
return rhs == lhs;
}
#endif
friend bool operator!=(const SmallVector& lhs, const std::vector<T>& rhs) {
return !(lhs == rhs);
@@ -363,7 +366,7 @@ class SmallVector {
}
}
// Upate the size.
// Update the size.
size_ += num_of_new_elements;
return pos;
}
@@ -449,7 +452,7 @@ class SmallVector {
T* small_data_;
// The actual data used to store the array elements. It must never be used
// directly, but must only be accesed through |small_data_|.
// directly, but must only be accessed through |small_data_|.
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type
buffer[small_size];

View File

@@ -206,16 +206,16 @@ class Timer {
// Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
// Timer::Stop() is called. It is used as the last status of CPU time. The
// resouce usage is measured by subtracting |cpu_before_| from it.
// resource usage is measured by subtracting |cpu_before_| from it.
timespec cpu_after_;
// Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
// Timer::Stop() is called. It is used as the last status of WALL time. The
// resouce usage is measured by subtracting |wall_before_| from it.
// resource usage is measured by subtracting |wall_before_| from it.
timespec wall_after_;
// Variable to save the result of getrusage() when Timer::Stop() is called. It
// is used as the last status of USR time, SYS time, and RSS. Those resouce
// is used as the last status of USR time, SYS time, and RSS. Those resource
// usages are measured by subtracting |usage_before_| from it.
rusage usage_after_;

View File

@@ -84,26 +84,26 @@ class BasicBlock {
type_.set(type);
}
/// Sets the immedate dominator of this basic block
/// Sets the immediate dominator of this basic block
///
/// @param[in] dom_block The dominator block
void SetImmediateDominator(BasicBlock* dom_block);
/// Sets the immedate post dominator of this basic block
/// Sets the immediate post dominator of this basic block
///
/// @param[in] pdom_block The post dominator block
void SetImmediatePostDominator(BasicBlock* pdom_block);
/// Returns the immedate dominator of this basic block
/// Returns the immediate dominator of this basic block
BasicBlock* immediate_dominator();
/// Returns the immedate dominator of this basic block
/// Returns the immediate dominator of this basic block
const BasicBlock* immediate_dominator() const;
/// Returns the immedate post dominator of this basic block
/// Returns the immediate post dominator of this basic block
BasicBlock* immediate_post_dominator();
/// Returns the immedate post dominator of this basic block
/// Returns the immediate post dominator of this basic block
const BasicBlock* immediate_post_dominator() const;
/// Returns the label instruction for the block, or nullptr if not set.

View File

@@ -57,7 +57,7 @@ spv_result_t Function::RegisterFunctionParameter(uint32_t parameter_id,
uint32_t type_id) {
assert(current_block_ == nullptr &&
"RegisterFunctionParameter can only be called when parsing the binary "
"ouside of a block");
"outside of a block");
// TODO(umar): Validate function parameter type order and count
// TODO(umar): Use these variables to validate parameter type
(void)parameter_id;
@@ -130,7 +130,7 @@ spv_result_t Function::RegisterBlock(uint32_t block_id, bool is_definition) {
undefined_blocks_.erase(block_id);
current_block_ = &inserted_block->second;
ordered_blocks_.push_back(current_block_);
} else if (success) { // Block doesn't exsist but this is not a definition
} else if (success) { // Block doesn't exist but this is not a definition
undefined_blocks_.insert(block_id);
}

View File

@@ -73,8 +73,8 @@ class Function {
/// Registers a variable in the current block
///
/// @param[in] type_id The type ID of the varaible
/// @param[in] id The ID of the varaible
/// @param[in] type_id The type ID of the variable
/// @param[in] id The ID of the variable
/// @param[in] storage The storage of the variable
/// @param[in] init_id The initializer ID of the variable
///
@@ -197,10 +197,10 @@ class Function {
/// been identified and dominators have been computed.
int GetBlockDepth(BasicBlock* bb);
/// Prints a GraphViz digraph of the CFG of the current funciton
/// Prints a GraphViz digraph of the CFG of the current function
void PrintDotGraph() const;
/// Prints a directed graph of the CFG of the current funciton
/// Prints a directed graph of the CFG of the current function
void PrintBlocks() const;
/// Registers execution model limitation such as "Feature X is only available
@@ -285,7 +285,7 @@ class Function {
/// The type of the return value
uint32_t result_type_id_;
/// The control fo the funciton
/// The control fo the function
SpvFunctionControlMask function_control_;
/// The type of declaration of each function

View File

@@ -348,7 +348,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
}
// Validate the preconditions involving adjacent instructions. e.g. SpvOpPhi
// must only be preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
// must only be preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
if (auto error = ValidateAdjacency(*vstate)) return error;
if (auto error = ValidateEntryPoints(*vstate)) return error;

View File

@@ -70,7 +70,7 @@ spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _);
///
/// This function will iterate over all instructions and check for any required
/// predecessor and/or successor instructions. e.g. SpvOpPhi must only be
/// preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
/// preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine.
///
/// @param[in] _ the validation state of the module
///

View File

@@ -155,7 +155,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
first_vector_num_components = num_components;
} else if (num_components != first_vector_num_components) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected operands to have the same number of componenets: "
<< "Expected operands to have the same number of components: "
<< spvOpcodeString(opcode);
}
}

View File

@@ -675,7 +675,7 @@ spv_result_t ValidateStructuredSelections(
} else if (terminator->opcode() == SpvOpSwitch) {
if (!merge) {
return _.diag(SPV_ERROR_INVALID_CFG, terminator)
<< "OpSwitch must be preceeded by an OpSelectionMerge "
<< "OpSwitch must be preceded by an OpSelectionMerge "
"instruction";
}
// Mark the targets as seen.
@@ -917,7 +917,7 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) {
}
}
}
// If we have structed control flow, check that no block has a control
// If we have structured control flow, check that no block has a control
// flow nesting depth larger than the limit.
if (_.HasCapability(SpvCapabilityShader)) {
const int control_flow_nesting_depth_limit =

View File

@@ -465,7 +465,7 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
return lhs.offset < rhs.offset;
});
// Now scan from lowest offest to highest offset.
// Now scan from lowest offset to highest offset.
uint32_t nextValidOffset = 0;
for (size_t ordered_member_idx = 0;
ordered_member_idx < member_offsets.size(); ordered_member_idx++) {
@@ -720,7 +720,7 @@ spv_result_t CheckBuiltInVariable(uint32_t var_id, ValidationState_t& vstate) {
return SPV_SUCCESS;
}
// Checks whether proper decorations have been appied to the entry points.
// Checks whether proper decorations have been applied to the entry points.
spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
for (uint32_t entry_point : vstate.entry_points()) {
const auto& descs = vstate.entry_point_descriptions(entry_point);

View File

@@ -129,7 +129,7 @@ spv_result_t ValidateUint32ConstantOperandForDebugInfo(
}
// True if the operand of a debug info instruction |inst| at |word_index|
// satisifies |expectation| that is given as a function. Otherwise,
// satisfies |expectation| that is given as a function. Otherwise,
// returns false.
bool DoesDebugInfoOperandMatchExpectation(
const ValidationState_t& _,

View File

@@ -260,7 +260,8 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
SpvImageOperandsVolatileTexelKHRMask |
SpvImageOperandsSignExtendMask |
SpvImageOperandsZeroExtendMask);
SpvImageOperandsZeroExtendMask |
SpvImageOperandsNontemporalMask);
size_t expected_num_image_operand_words =
spvtools::utils::CountSetBits(mask_bits_having_operands);
if (mask & SpvImageOperandsGradMask) {
@@ -502,7 +503,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
if (!_.IsIntVectorType(component_type) ||
_.GetDimension(component_type) != 2) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image Operand ConstOffsets array componenets to be "
<< "Expected Image Operand ConstOffsets array components to be "
"int vectors of size 2";
}
@@ -1043,7 +1044,7 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
<< "Result <id> from OpSampledImage instruction must not appear "
"as operand for Op"
<< spvOpcodeString(static_cast<SpvOp>(consumer_opcode))
<< ", since it is not specificed as taking an "
<< ", since it is not specified as taking an "
<< "OpTypeSampledImage."
<< " Found result <id> '" << _.getIdName(inst->id())
<< "' as an operand of <id> '"
@@ -1672,7 +1673,7 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) {
<< " components, but given only " << actual_coord_size;
}
// TODO(atgoo@github.com) The spec doesn't explicitely say what the type
// TODO(atgoo@github.com) The spec doesn't explicitly say what the type
// of texel should be.
const uint32_t texel_type = _.GetOperandTypeId(inst, 2);
if (!_.IsIntScalarOrVectorType(texel_type) &&

View File

@@ -297,7 +297,7 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) {
}
// OpTerminateInvocation is special because it is enabled by Shader
// capability, but also requries a extension and/or version check.
// capability, but also requires an extension and/or version check.
const bool capability_check_is_sufficient =
inst->opcode() != SpvOpTerminateInvocation;
@@ -406,7 +406,7 @@ spv_result_t LimitCheckSwitch(ValidationState_t& _, const Instruction* inst) {
// The instruction syntax is as follows:
// OpSwitch <selector ID> <Default ID> literal label literal label ...
// literal,label pairs come after the first 2 operands.
// It is guaranteed at this point that num_operands is an even numner.
// It is guaranteed at this point that num_operands is an even number.
size_t num_pairs = (inst->operands().size() - 2) / 2;
const unsigned int num_pairs_limit =
_.options()->universal_limits_.max_switch_branches;

View File

@@ -225,7 +225,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
<< _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan environment, Memory Scope cannot be CrossDevice";
}
// Vulkan 1.0 specifc rules
// Vulkan 1.0 specific rules
if (_.context()->target_env == SPV_ENV_VULKAN_1_0 &&
value != SpvScopeDevice && value != SpvScopeWorkgroup &&
value != SpvScopeInvocation) {
@@ -234,7 +234,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst,
<< ": in Vulkan 1.0 environment Memory Scope is limited to "
<< "Device, Workgroup and Invocation";
}
// Vulkan 1.1 specifc rules
// Vulkan 1.1 specific rules
if ((_.context()->target_env == SPV_ENV_VULKAN_1_1 ||
_.context()->target_env == SPV_ENV_VULKAN_1_2) &&
value != SpvScopeDevice && value != SpvScopeWorkgroup &&

View File

@@ -175,7 +175,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx,
}
}
// LocalSizeId is only disallowed without maintainence4.
// LocalSizeId is only disallowed prior to Vulkan 1.3 without maintenance4.
switch (env) {
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_1:
@@ -498,7 +498,7 @@ spv_result_t ValidationState_t::RegisterFunctionEnd() {
"inside of another function");
assert(in_block() == false &&
"RegisterFunctionParameter can only be called when parsing the binary "
"ouside of a block");
"outside of a block");
current_function().RegisterFunctionEnd();
in_function_ = false;
return SPV_SUCCESS;
@@ -610,7 +610,7 @@ void ValidationState_t::RegisterStorageClassConsumer(
if (message) {
*message =
errorVUID +
"in Vulkan evironment, Output Storage Class must not be "
"in Vulkan environment, Output Storage Class must not be "
"used in GLCompute, RayGenerationKHR, IntersectionKHR, "
"AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR "
"execution models";
@@ -632,7 +632,7 @@ void ValidationState_t::RegisterStorageClassConsumer(
if (message) {
*message =
errorVUID +
"in Vulkan evironment, Workgroup Storage Class is limited "
"in Vulkan environment, Workgroup Storage Class is limited "
"to MeshNV, TaskNV, and GLCompute execution model";
}
return false;
@@ -1407,7 +1407,7 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return "";
}
// This large switch case is only searched when an error has occured.
// This large switch case is only searched when an error has occurred.
// If an id is changed, the old case must be modified or removed. Each string
// here is interpreted as being "implemented"

View File

@@ -67,7 +67,7 @@ class ValidationState_t {
bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width?
bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width?
bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration
// and its vaules to be used without
// and its values to be used without
// requiring any capability
// Allow functionalities enabled by VariablePointers capability.
@@ -797,7 +797,7 @@ class ValidationState_t {
/// IDs that are entry points, ie, arguments to OpEntryPoint.
std::vector<uint32_t> entry_points_;
/// Maps an entry point id to its desciptions.
/// Maps an entry point id to its descriptions.
std::unordered_map<uint32_t, std::vector<EntryPointDescription>>
entry_point_descriptions_;
@@ -844,7 +844,7 @@ class ValidationState_t {
// have the same pointer size (for physical pointer types).
uint32_t pointer_size_and_alignment_;
/// NOTE: See correspoding getter functions
/// NOTE: See corresponding getter functions
bool in_function_;
/// The state of optional features. These are determined by capabilities