mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-20 13:53:14 +01:00
Updated spirv-tools.
This commit is contained in:
@@ -1 +1 @@
|
||||
"v2023.3", "SPIRV-Tools v2023.3 v2022.4-269-g34399abb"
|
||||
"v2023.4", "SPIRV-Tools v2023.4 v2022.4-291-ga913df4a"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -37,6 +37,7 @@ kSPV_INTEL_debug_module,
|
||||
kSPV_INTEL_device_side_avc_motion_estimation,
|
||||
kSPV_INTEL_float_controls2,
|
||||
kSPV_INTEL_fp_fast_math_mode,
|
||||
kSPV_INTEL_fp_max_error,
|
||||
kSPV_INTEL_fpga_argument_interfaces,
|
||||
kSPV_INTEL_fpga_buffer_location,
|
||||
kSPV_INTEL_fpga_cluster_attributes,
|
||||
|
||||
@@ -27,6 +27,7 @@ static const spv::Capability pygen_variable_caps_FPGALatencyControlINTEL[] = {sp
|
||||
static const spv::Capability pygen_variable_caps_FPGALoopControlsINTEL[] = {spv::Capability::FPGALoopControlsINTEL};
|
||||
static const spv::Capability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {spv::Capability::FPGAMemoryAccessesINTEL};
|
||||
static const spv::Capability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {spv::Capability::FPGAMemoryAttributesINTEL};
|
||||
static const spv::Capability pygen_variable_caps_FPMaxErrorINTEL[] = {spv::Capability::FPMaxErrorINTEL};
|
||||
static const spv::Capability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {spv::Capability::FragmentBarycentricNV, spv::Capability::FragmentBarycentricKHR};
|
||||
static const spv::Capability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {spv::Capability::FragmentDensityEXT, spv::Capability::ShadingRateNV};
|
||||
static const spv::Capability pygen_variable_caps_FragmentFullyCoveredEXT[] = {spv::Capability::FragmentFullyCoveredEXT};
|
||||
@@ -169,6 +170,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_debug_module[] =
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_device_side_avc_motion_estimation[] = {spvtools::Extension::kSPV_INTEL_device_side_avc_motion_estimation};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_float_controls2[] = {spvtools::Extension::kSPV_INTEL_float_controls2};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fp_fast_math_mode[] = {spvtools::Extension::kSPV_INTEL_fp_fast_math_mode};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fp_max_error[] = {spvtools::Extension::kSPV_INTEL_fp_max_error};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces[] = {spvtools::Extension::kSPV_INTEL_fpga_argument_interfaces};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_buffer_location[] = {spvtools::Extension::kSPV_INTEL_fpga_buffer_location};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_cluster_attributes[] = {spvtools::Extension::kSPV_INTEL_fpga_cluster_attributes};
|
||||
@@ -855,6 +857,7 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
|
||||
{"SingleElementVectorINTEL", 6085, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"VectorComputeCallableFunctionINTEL", 6087, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MediaBlockIOINTEL", 6140, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"FPMaxErrorDecorationINTEL", 6170, 1, pygen_variable_caps_FPMaxErrorINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_FLOAT}, 0xffffffffu, 0xffffffffu},
|
||||
{"LatencyControlLabelINTEL", 6172, 1, pygen_variable_caps_FPGALatencyControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
|
||||
{"LatencyControlConstraintINTEL", 6173, 1, pygen_variable_caps_FPGALatencyControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
|
||||
{"ConduitKernelArgumentINTEL", 6175, 1, pygen_variable_caps_FPGAArgumentInterfacesINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
@@ -1272,6 +1275,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
|
||||
{"BFloat16ConversionINTEL", 6115, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_bfloat16_conversion, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"SplitBarrierINTEL", 6141, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_split_barrier, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"FPGAKernelAttributesv2INTEL", 6161, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"FPMaxErrorINTEL", 6169, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fp_max_error, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"FPGALatencyControlINTEL", 6171, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_latency_control, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"FPGAArgumentInterfacesINTEL", 6174, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"GroupUniformArithmeticKHR", 6400, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_uniform_group_instructions, {}, 0xffffffffu, 0xffffffffu}
|
||||
@@ -1299,12 +1303,12 @@ static const spv_operand_desc_t pygen_variable_PackedVectorFormatEntries[] = {
|
||||
};
|
||||
|
||||
static const spv_operand_desc_t pygen_variable_CooperativeMatrixOperandsEntries[] = {
|
||||
{"None", 0x0000, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixASignedComponents", 0x0001, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixBSignedComponents", 0x0002, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixCSignedComponents", 0x0004, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixResultSignedComponents", 0x0008, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"SaturatingAccumulation", 0x0010, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
|
||||
{"NoneKHR", 0x0000, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixASignedComponentsKHR", 0x0001, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixBSignedComponentsKHR", 0x0002, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixCSignedComponentsKHR", 0x0004, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"MatrixResultSignedComponentsKHR", 0x0008, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"SaturatingAccumulationKHR", 0x0010, 1, pygen_variable_caps_CooperativeMatrixKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
|
||||
};
|
||||
|
||||
static const spv_operand_desc_t pygen_variable_CooperativeMatrixLayoutEntries[] = {
|
||||
|
||||
@@ -143,6 +143,7 @@ typedef enum spv_operand_type_t {
|
||||
// may be larger than 32, which would require such a typed literal value to
|
||||
// occupy multiple SPIR-V words.
|
||||
SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
|
||||
SPV_OPERAND_TYPE_LITERAL_FLOAT, // Always 32-bit float.
|
||||
|
||||
// Set 3: The literal string operand type.
|
||||
SPV_OPERAND_TYPE_LITERAL_STRING,
|
||||
|
||||
@@ -981,6 +981,17 @@ Optimizer::PassToken CreateRemoveDontInlinePass();
|
||||
// object, currently the pass would remove accesschain pointer argument passed
|
||||
// to the function
|
||||
Optimizer::PassToken CreateFixFuncCallArgumentsPass();
|
||||
|
||||
// Creates a trim-capabilities pass.
|
||||
// This pass removes unused capabilities for a given module, and if possible,
|
||||
// associated extensions.
|
||||
// See `trim_capabilities.h` for the list of supported capabilities.
|
||||
//
|
||||
// If the module contains unsupported capabilities, this pass will ignore them.
|
||||
// This should be fine in most cases, but could yield to incorrect results if
|
||||
// the unknown capability interacts with one of the trimmed capabilities.
|
||||
Optimizer::PassToken CreateTrimCapabilitiesPass();
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
|
||||
|
||||
7
3rdparty/spirv-tools/source/binary.cpp
vendored
7
3rdparty/spirv-tools/source/binary.cpp
vendored
@@ -546,6 +546,13 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
parsed_operand.number_bit_width = 32;
|
||||
break;
|
||||
|
||||
case SPV_OPERAND_TYPE_LITERAL_FLOAT:
|
||||
// These are regular single-word literal float operands.
|
||||
parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT;
|
||||
parsed_operand.number_kind = SPV_NUMBER_FLOATING;
|
||||
parsed_operand.number_bit_width = 32;
|
||||
break;
|
||||
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
||||
parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
|
||||
|
||||
4
3rdparty/spirv-tools/source/diff/diff.cpp
vendored
4
3rdparty/spirv-tools/source/diff/diff.cpp
vendored
@@ -2038,6 +2038,10 @@ spv_number_kind_t Differ::GetNumberKind(const IdInstructions& id_to,
|
||||
// Always unsigned integers.
|
||||
*number_bit_width = 32;
|
||||
return SPV_NUMBER_UNSIGNED_INT;
|
||||
case SPV_OPERAND_TYPE_LITERAL_FLOAT:
|
||||
// Always float.
|
||||
*number_bit_width = 32;
|
||||
return SPV_NUMBER_FLOATING;
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
||||
switch (inst.opcode()) {
|
||||
|
||||
3
3rdparty/spirv-tools/source/disassemble.cpp
vendored
3
3rdparty/spirv-tools/source/disassemble.cpp
vendored
@@ -357,7 +357,8 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst,
|
||||
stream_ << opcode_desc->name;
|
||||
} break;
|
||||
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
|
||||
case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
|
||||
SetRed();
|
||||
EmitNumericLiteral(&stream_, inst, operand);
|
||||
ResetColor();
|
||||
|
||||
18
3rdparty/spirv-tools/source/enum_set.h
vendored
18
3rdparty/spirv-tools/source/enum_set.h
vendored
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@@ -203,6 +204,14 @@ class EnumSet {
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a set initialized with the content of the range [begin; end[.
|
||||
template <class InputIt>
|
||||
EnumSet(InputIt begin, InputIt end) : EnumSet() {
|
||||
for (; begin != end; ++begin) {
|
||||
insert(*begin);
|
||||
}
|
||||
}
|
||||
|
||||
// Copies the EnumSet `other` into a new EnumSet.
|
||||
EnumSet(const EnumSet& other)
|
||||
: buckets_(other.buckets_), size_(other.size_) {}
|
||||
@@ -255,6 +264,15 @@ class EnumSet {
|
||||
// insertion.
|
||||
iterator insert(const_iterator, T&& value) { return insert(value).first; }
|
||||
|
||||
// Inserts all the values in the range [`first`; `last[.
|
||||
// Similar to `std::unordered_set::insert`.
|
||||
template <class InputIt>
|
||||
void insert(InputIt first, InputIt last) {
|
||||
for (auto it = first; it != last; ++it) {
|
||||
insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// Removes the value `value` into the set.
|
||||
// Similar to `std::unordered_set::erase`.
|
||||
// Returns the number of erased elements.
|
||||
|
||||
2
3rdparty/spirv-tools/source/operand.cpp
vendored
2
3rdparty/spirv-tools/source/operand.cpp
vendored
@@ -155,6 +155,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
|
||||
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
|
||||
case SPV_OPERAND_TYPE_LITERAL_FLOAT:
|
||||
return "literal number";
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
||||
return "possibly multi-word literal integer";
|
||||
@@ -332,6 +333,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) {
|
||||
}
|
||||
switch (type) {
|
||||
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
|
||||
case SPV_OPERAND_TYPE_LITERAL_FLOAT:
|
||||
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
|
||||
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
|
||||
|
||||
@@ -438,6 +438,9 @@ std::vector<uint32_t> AggressiveDCEPass::GetLoadedVariablesFromFunctionCall(
|
||||
const Instruction* inst) {
|
||||
assert(inst->opcode() == spv::Op::OpFunctionCall);
|
||||
std::vector<uint32_t> live_variables;
|
||||
// NOTE: we should only be checking function call parameters here, not the
|
||||
// function itself, however, `IsPtr` will trivially return false for
|
||||
// OpFunction
|
||||
inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) {
|
||||
if (!IsPtr(*operand_id)) return;
|
||||
uint32_t var_id = GetVariableId(*operand_id);
|
||||
@@ -995,6 +998,7 @@ void AggressiveDCEPass::InitExtensions() {
|
||||
"SPV_KHR_uniform_group_instructions",
|
||||
"SPV_KHR_fragment_shader_barycentric",
|
||||
"SPV_NV_bindless_texture",
|
||||
"SPV_EXT_shader_atomic_float_add",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -967,6 +967,11 @@ const analysis::Constant* FoldScalarFPDivide(
|
||||
return FoldFPScalarDivideByZero(result_type, numerator, const_mgr);
|
||||
}
|
||||
|
||||
uint32_t width = denominator->type()->AsFloat()->width();
|
||||
if (width != 32 && width != 64) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const analysis::FloatConstant* denominator_float =
|
||||
denominator->AsFloatConstant();
|
||||
if (denominator_float && denominator->GetValueAsDouble() == -0.0) {
|
||||
|
||||
@@ -63,6 +63,10 @@ bool ConvertToHalfPass::IsRelaxed(uint32_t id) {
|
||||
|
||||
void ConvertToHalfPass::AddRelaxed(uint32_t id) { relaxed_ids_set_.insert(id); }
|
||||
|
||||
bool ConvertToHalfPass::CanRelaxOpOperands(Instruction* inst) {
|
||||
return image_ops_.count(inst->opcode()) == 0;
|
||||
}
|
||||
|
||||
analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) {
|
||||
analysis::Float float_ty(width);
|
||||
return context()->get_type_mgr()->GetRegisteredType(&float_ty);
|
||||
@@ -313,7 +317,8 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) {
|
||||
relax = true;
|
||||
get_def_use_mgr()->ForEachUser(inst, [&relax, this](Instruction* uinst) {
|
||||
if (uinst->result_id() == 0 || !IsFloat(uinst, 32) ||
|
||||
(!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id()))) {
|
||||
(!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id())) ||
|
||||
!CanRelaxOpOperands(uinst)) {
|
||||
relax = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,9 @@ class ConvertToHalfPass : public Pass {
|
||||
// Add |id| to the relaxed id set
|
||||
void AddRelaxed(uint32_t id);
|
||||
|
||||
// Return true if the instruction's operands can be relaxed
|
||||
bool CanRelaxOpOperands(Instruction* inst);
|
||||
|
||||
// Return type id for float with |width|
|
||||
analysis::Type* FloatScalarType(uint32_t width);
|
||||
|
||||
@@ -133,13 +136,13 @@ class ConvertToHalfPass : public Pass {
|
||||
// Set of 450 extension operations to be processed
|
||||
std::unordered_set<uint32_t> target_ops_450_;
|
||||
|
||||
// Set of sample operations
|
||||
// Set of all sample operations, including dref and non-dref operations
|
||||
std::unordered_set<spv::Op, hasher> image_ops_;
|
||||
|
||||
// Set of dref sample operations
|
||||
// Set of only dref sample operations
|
||||
std::unordered_set<spv::Op, hasher> dref_image_ops_;
|
||||
|
||||
// Set of dref sample operations
|
||||
// Set of operations that can be marked as relaxed
|
||||
std::unordered_set<spv::Op, hasher> closure_ops_;
|
||||
|
||||
// Set of ids of all relaxed instructions
|
||||
|
||||
@@ -25,27 +25,19 @@ namespace opt {
|
||||
// Tracks features enabled by a module. The IRContext has a FeatureManager.
|
||||
class FeatureManager {
|
||||
public:
|
||||
explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {}
|
||||
|
||||
// Returns true if |ext| is an enabled extension in the module.
|
||||
bool HasExtension(Extension ext) const { return extensions_.contains(ext); }
|
||||
|
||||
// Removes the given |extension| from the current FeatureManager.
|
||||
void RemoveExtension(Extension extension);
|
||||
|
||||
// Returns true if |cap| is an enabled capability in the module.
|
||||
bool HasCapability(spv::Capability cap) const {
|
||||
return capabilities_.contains(cap);
|
||||
}
|
||||
|
||||
// Removes the given |capability| from the current FeatureManager.
|
||||
void RemoveCapability(spv::Capability capability);
|
||||
// Returns the capabilities the module declares.
|
||||
inline const CapabilitySet& GetCapabilities() const { return capabilities_; }
|
||||
|
||||
// Analyzes |module| and records enabled extensions and capabilities.
|
||||
void Analyze(Module* module);
|
||||
|
||||
CapabilitySet* GetCapabilities() { return &capabilities_; }
|
||||
const CapabilitySet* GetCapabilities() const { return &capabilities_; }
|
||||
// Returns the extensions the module imports.
|
||||
inline const ExtensionSet& GetExtensions() const { return extensions_; }
|
||||
|
||||
uint32_t GetExtInstImportId_GLSLstd450() const {
|
||||
return extinst_importid_GLSLstd450_;
|
||||
@@ -64,23 +56,34 @@ class FeatureManager {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Adds the given |capability| and all implied capabilities into the current
|
||||
// FeatureManager.
|
||||
void AddCapability(spv::Capability capability);
|
||||
private:
|
||||
explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {}
|
||||
|
||||
// Analyzes |module| and records enabled extensions and capabilities.
|
||||
void Analyze(Module* module);
|
||||
|
||||
// Add the extension |ext| to the feature manager.
|
||||
void AddExtension(Instruction* ext);
|
||||
|
||||
// Analyzes |module| and records imported external instruction sets.
|
||||
void AddExtInstImportIds(Module* module);
|
||||
|
||||
private:
|
||||
// Analyzes |module| and records enabled extensions.
|
||||
void AddExtensions(Module* module);
|
||||
|
||||
// Removes the given |extension| from the current FeatureManager.
|
||||
void RemoveExtension(Extension extension);
|
||||
|
||||
// Adds the given |capability| and all implied capabilities into the current
|
||||
// FeatureManager.
|
||||
void AddCapability(spv::Capability capability);
|
||||
|
||||
// Analyzes |module| and records enabled capabilities.
|
||||
void AddCapabilities(Module* module);
|
||||
|
||||
// Removes the given |capability| from the current FeatureManager.
|
||||
void RemoveCapability(spv::Capability capability);
|
||||
|
||||
// Analyzes |module| and records imported external instruction sets.
|
||||
void AddExtInstImportIds(Module* module);
|
||||
|
||||
// Auxiliary object for querying SPIR-V grammar facts.
|
||||
const AssemblyGrammar& grammar_;
|
||||
|
||||
@@ -100,6 +103,8 @@ class FeatureManager {
|
||||
// Common NonSemanticShader100DebugInfo external instruction import ids,
|
||||
// cached for performance.
|
||||
uint32_t extinst_importid_Shader100DebugInfo_ = 0;
|
||||
|
||||
friend class IRContext;
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
|
||||
@@ -573,9 +573,9 @@ uint32_t GraphicsRobustAccessPass::GetGlslInsts() {
|
||||
context()->module()->AddExtInstImport(std::move(import_inst));
|
||||
module_status_.modified = true;
|
||||
context()->AnalyzeDefUse(inst);
|
||||
// Reanalyze the feature list, since we added an extended instruction
|
||||
// set improt.
|
||||
context()->get_feature_mgr()->Analyze(context()->module());
|
||||
// Invalidates the feature manager, since we added an extended instruction
|
||||
// set import.
|
||||
context()->ResetFeatureManager();
|
||||
}
|
||||
}
|
||||
return module_status_.glsl_insts_id;
|
||||
|
||||
@@ -241,15 +241,7 @@ Pass::Status InstDebugPrintfPass::ProcessImpl() {
|
||||
}
|
||||
}
|
||||
if (!non_sem_set_seen) {
|
||||
for (auto c_itr = context()->module()->extension_begin();
|
||||
c_itr != context()->module()->extension_end(); ++c_itr) {
|
||||
const std::string ext_name = c_itr->GetInOperand(0).AsString();
|
||||
if (ext_name == "SPV_KHR_non_semantic_info") {
|
||||
context()->KillInst(&*c_itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context()->get_feature_mgr()->RemoveExtension(kSPV_KHR_non_semantic_info);
|
||||
context()->RemoveExtension(kSPV_KHR_non_semantic_info);
|
||||
}
|
||||
return Status::SuccessWithChange;
|
||||
}
|
||||
|
||||
54
3rdparty/spirv-tools/source/opt/ir_context.cpp
vendored
54
3rdparty/spirv-tools/source/opt/ir_context.cpp
vendored
@@ -220,6 +220,28 @@ Instruction* IRContext::KillInst(Instruction* inst) {
|
||||
return next_instruction;
|
||||
}
|
||||
|
||||
bool IRContext::KillInstructionIf(Module::inst_iterator begin,
|
||||
Module::inst_iterator end,
|
||||
std::function<bool(Instruction*)> condition) {
|
||||
bool removed = false;
|
||||
for (auto it = begin; it != end;) {
|
||||
if (!condition(&*it)) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
removed = true;
|
||||
// `it` is an iterator on an intrusive list. Next is invalidated on the
|
||||
// current node when an instruction is killed. The iterator must be moved
|
||||
// forward before deleting the node.
|
||||
auto instruction = &*it;
|
||||
++it;
|
||||
KillInst(instruction);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
void IRContext::CollectNonSemanticTree(
|
||||
Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
|
||||
if (!inst->HasResultId()) return;
|
||||
@@ -251,6 +273,36 @@ bool IRContext::KillDef(uint32_t id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRContext::RemoveCapability(spv::Capability capability) {
|
||||
const bool removed = KillInstructionIf(
|
||||
module()->capability_begin(), module()->capability_end(),
|
||||
[capability](Instruction* inst) {
|
||||
return static_cast<spv::Capability>(inst->GetSingleWordOperand(0)) ==
|
||||
capability;
|
||||
});
|
||||
|
||||
if (removed && feature_mgr_ != nullptr) {
|
||||
feature_mgr_->RemoveCapability(capability);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool IRContext::RemoveExtension(Extension extension) {
|
||||
const std::string_view extensionName = ExtensionToString(extension);
|
||||
const bool removed = KillInstructionIf(
|
||||
module()->extension_begin(), module()->extension_end(),
|
||||
[&extensionName](Instruction* inst) {
|
||||
return inst->GetOperand(0).AsString() == extensionName;
|
||||
});
|
||||
|
||||
if (removed && feature_mgr_ != nullptr) {
|
||||
feature_mgr_->RemoveExtension(extension);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
|
||||
return ReplaceAllUsesWithPredicate(before, after,
|
||||
[](Instruction*) { return true; });
|
||||
@@ -718,7 +770,7 @@ void IRContext::AddCombinatorsForExtension(Instruction* extension) {
|
||||
}
|
||||
|
||||
void IRContext::InitializeCombinators() {
|
||||
for (auto capability : *get_feature_mgr()->GetCapabilities()) {
|
||||
for (auto capability : get_feature_mgr()->GetCapabilities()) {
|
||||
AddCombinatorsForCapability(uint32_t(capability));
|
||||
}
|
||||
|
||||
|
||||
46
3rdparty/spirv-tools/source/opt/ir_context.h
vendored
46
3rdparty/spirv-tools/source/opt/ir_context.h
vendored
@@ -27,6 +27,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "source/assembly_grammar.h"
|
||||
#include "source/enum_string_mapping.h"
|
||||
#include "source/opt/cfg.h"
|
||||
#include "source/opt/constants.h"
|
||||
#include "source/opt/debug_info_manager.h"
|
||||
@@ -153,13 +154,19 @@ class IRContext {
|
||||
inline IteratorRange<Module::inst_iterator> capabilities();
|
||||
inline IteratorRange<Module::const_inst_iterator> capabilities() const;
|
||||
|
||||
// Iterators for extensions instructions contained in this module.
|
||||
inline Module::inst_iterator extension_begin();
|
||||
inline Module::inst_iterator extension_end();
|
||||
inline IteratorRange<Module::inst_iterator> extensions();
|
||||
inline IteratorRange<Module::const_inst_iterator> extensions() const;
|
||||
|
||||
// Iterators for types, constants and global variables instructions.
|
||||
inline Module::inst_iterator types_values_begin();
|
||||
inline Module::inst_iterator types_values_end();
|
||||
inline IteratorRange<Module::inst_iterator> types_values();
|
||||
inline IteratorRange<Module::const_inst_iterator> types_values() const;
|
||||
|
||||
// Iterators for extension instructions contained in this module.
|
||||
// Iterators for ext_inst import instructions contained in this module.
|
||||
inline Module::inst_iterator ext_inst_import_begin();
|
||||
inline Module::inst_iterator ext_inst_import_end();
|
||||
inline IteratorRange<Module::inst_iterator> ext_inst_imports();
|
||||
@@ -204,12 +211,19 @@ class IRContext {
|
||||
|
||||
// Add |capability| to the module, if it is not already enabled.
|
||||
inline void AddCapability(spv::Capability capability);
|
||||
|
||||
// Appends a capability instruction to this module.
|
||||
inline void AddCapability(std::unique_ptr<Instruction>&& c);
|
||||
// Removes instruction declaring `capability` from this module.
|
||||
// Returns true if the capability was removed, false otherwise.
|
||||
bool RemoveCapability(spv::Capability capability);
|
||||
|
||||
// Appends an extension instruction to this module.
|
||||
inline void AddExtension(const std::string& ext_name);
|
||||
inline void AddExtension(std::unique_ptr<Instruction>&& e);
|
||||
// Removes instruction declaring `extension` from this module.
|
||||
// Returns true if the extension was removed, false otherwise.
|
||||
bool RemoveExtension(Extension extension);
|
||||
|
||||
// Appends an extended instruction set instruction to this module.
|
||||
inline void AddExtInstImport(const std::string& name);
|
||||
inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
|
||||
@@ -422,6 +436,15 @@ class IRContext {
|
||||
// instruction exists.
|
||||
Instruction* KillInst(Instruction* inst);
|
||||
|
||||
// Deletes all the instruction in the range [`begin`; `end`[, for which the
|
||||
// unary predicate `condition` returned true.
|
||||
// Returns true if at least one instruction was removed, false otherwise.
|
||||
//
|
||||
// Pointer and iterator pointing to the deleted instructions become invalid.
|
||||
// However other pointers and iterators are still valid.
|
||||
bool KillInstructionIf(Module::inst_iterator begin, Module::inst_iterator end,
|
||||
std::function<bool(Instruction*)> condition);
|
||||
|
||||
// Collects the non-semantic instruction tree that uses |inst|'s result id
|
||||
// to be killed later.
|
||||
void CollectNonSemanticTree(Instruction* inst,
|
||||
@@ -772,7 +795,8 @@ class IRContext {
|
||||
|
||||
// Analyzes the features in the owned module. Builds the manager if required.
|
||||
void AnalyzeFeatures() {
|
||||
feature_mgr_ = MakeUnique<FeatureManager>(grammar_);
|
||||
feature_mgr_ =
|
||||
std::unique_ptr<FeatureManager>(new FeatureManager(grammar_));
|
||||
feature_mgr_->Analyze(module());
|
||||
}
|
||||
|
||||
@@ -964,6 +988,22 @@ IteratorRange<Module::const_inst_iterator> IRContext::capabilities() const {
|
||||
return ((const Module*)module())->capabilities();
|
||||
}
|
||||
|
||||
Module::inst_iterator IRContext::extension_begin() {
|
||||
return module()->extension_begin();
|
||||
}
|
||||
|
||||
Module::inst_iterator IRContext::extension_end() {
|
||||
return module()->extension_end();
|
||||
}
|
||||
|
||||
IteratorRange<Module::inst_iterator> IRContext::extensions() {
|
||||
return module()->extensions();
|
||||
}
|
||||
|
||||
IteratorRange<Module::const_inst_iterator> IRContext::extensions() const {
|
||||
return ((const Module*)module())->extensions();
|
||||
}
|
||||
|
||||
Module::inst_iterator IRContext::types_values_begin() {
|
||||
return module()->types_values_begin();
|
||||
}
|
||||
|
||||
@@ -427,7 +427,7 @@ void LocalAccessChainConvertPass::InitExtensions() {
|
||||
"SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info",
|
||||
"SPV_KHR_uniform_group_instructions",
|
||||
"SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model",
|
||||
"SPV_NV_bindless_texture"});
|
||||
"SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add"});
|
||||
}
|
||||
|
||||
bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds(
|
||||
|
||||
@@ -233,62 +233,61 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() {
|
||||
|
||||
void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
|
||||
extensions_allowlist_.clear();
|
||||
extensions_allowlist_.insert({
|
||||
"SPV_AMD_shader_explicit_vertex_parameter",
|
||||
"SPV_AMD_shader_trinary_minmax",
|
||||
"SPV_AMD_gcn_shader",
|
||||
"SPV_KHR_shader_ballot",
|
||||
"SPV_AMD_shader_ballot",
|
||||
"SPV_AMD_gpu_shader_half_float",
|
||||
"SPV_KHR_shader_draw_parameters",
|
||||
"SPV_KHR_subgroup_vote",
|
||||
"SPV_KHR_8bit_storage",
|
||||
"SPV_KHR_16bit_storage",
|
||||
"SPV_KHR_device_group",
|
||||
"SPV_KHR_multiview",
|
||||
"SPV_NVX_multiview_per_view_attributes",
|
||||
"SPV_NV_viewport_array2",
|
||||
"SPV_NV_stereo_view_rendering",
|
||||
"SPV_NV_sample_mask_override_coverage",
|
||||
"SPV_NV_geometry_shader_passthrough",
|
||||
"SPV_AMD_texture_gather_bias_lod",
|
||||
"SPV_KHR_storage_buffer_storage_class",
|
||||
"SPV_KHR_variable_pointers",
|
||||
"SPV_AMD_gpu_shader_int16",
|
||||
"SPV_KHR_post_depth_coverage",
|
||||
"SPV_KHR_shader_atomic_counter_ops",
|
||||
"SPV_EXT_shader_stencil_export",
|
||||
"SPV_EXT_shader_viewport_index_layer",
|
||||
"SPV_AMD_shader_image_load_store_lod",
|
||||
"SPV_AMD_shader_fragment_mask",
|
||||
"SPV_EXT_fragment_fully_covered",
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_demote_to_helper_invocation",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
"SPV_NV_compute_shader_derivatives",
|
||||
"SPV_NV_shader_image_footprint",
|
||||
"SPV_NV_shading_rate",
|
||||
"SPV_NV_mesh_shader",
|
||||
"SPV_NV_ray_tracing",
|
||||
"SPV_KHR_ray_tracing",
|
||||
"SPV_KHR_ray_query",
|
||||
"SPV_EXT_fragment_invocation_density",
|
||||
"SPV_EXT_physical_storage_buffer",
|
||||
"SPV_KHR_terminate_invocation",
|
||||
"SPV_KHR_subgroup_uniform_control_flow",
|
||||
"SPV_KHR_integer_dot_product",
|
||||
"SPV_EXT_shader_image_int64",
|
||||
"SPV_KHR_non_semantic_info",
|
||||
"SPV_KHR_uniform_group_instructions",
|
||||
"SPV_KHR_fragment_shader_barycentric",
|
||||
"SPV_KHR_vulkan_memory_model",
|
||||
"SPV_NV_bindless_texture",
|
||||
});
|
||||
extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter",
|
||||
"SPV_AMD_shader_trinary_minmax",
|
||||
"SPV_AMD_gcn_shader",
|
||||
"SPV_KHR_shader_ballot",
|
||||
"SPV_AMD_shader_ballot",
|
||||
"SPV_AMD_gpu_shader_half_float",
|
||||
"SPV_KHR_shader_draw_parameters",
|
||||
"SPV_KHR_subgroup_vote",
|
||||
"SPV_KHR_8bit_storage",
|
||||
"SPV_KHR_16bit_storage",
|
||||
"SPV_KHR_device_group",
|
||||
"SPV_KHR_multiview",
|
||||
"SPV_NVX_multiview_per_view_attributes",
|
||||
"SPV_NV_viewport_array2",
|
||||
"SPV_NV_stereo_view_rendering",
|
||||
"SPV_NV_sample_mask_override_coverage",
|
||||
"SPV_NV_geometry_shader_passthrough",
|
||||
"SPV_AMD_texture_gather_bias_lod",
|
||||
"SPV_KHR_storage_buffer_storage_class",
|
||||
"SPV_KHR_variable_pointers",
|
||||
"SPV_AMD_gpu_shader_int16",
|
||||
"SPV_KHR_post_depth_coverage",
|
||||
"SPV_KHR_shader_atomic_counter_ops",
|
||||
"SPV_EXT_shader_stencil_export",
|
||||
"SPV_EXT_shader_viewport_index_layer",
|
||||
"SPV_AMD_shader_image_load_store_lod",
|
||||
"SPV_AMD_shader_fragment_mask",
|
||||
"SPV_EXT_fragment_fully_covered",
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_demote_to_helper_invocation",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
"SPV_NV_compute_shader_derivatives",
|
||||
"SPV_NV_shader_image_footprint",
|
||||
"SPV_NV_shading_rate",
|
||||
"SPV_NV_mesh_shader",
|
||||
"SPV_NV_ray_tracing",
|
||||
"SPV_KHR_ray_tracing",
|
||||
"SPV_KHR_ray_query",
|
||||
"SPV_EXT_fragment_invocation_density",
|
||||
"SPV_EXT_physical_storage_buffer",
|
||||
"SPV_KHR_terminate_invocation",
|
||||
"SPV_KHR_subgroup_uniform_control_flow",
|
||||
"SPV_KHR_integer_dot_product",
|
||||
"SPV_EXT_shader_image_int64",
|
||||
"SPV_KHR_non_semantic_info",
|
||||
"SPV_KHR_uniform_group_instructions",
|
||||
"SPV_KHR_fragment_shader_barycentric",
|
||||
"SPV_KHR_vulkan_memory_model",
|
||||
"SPV_NV_bindless_texture",
|
||||
"SPV_EXT_shader_atomic_float_add"});
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
|
||||
@@ -86,59 +86,58 @@ Pass::Status LocalSingleStoreElimPass::Process() {
|
||||
}
|
||||
|
||||
void LocalSingleStoreElimPass::InitExtensionAllowList() {
|
||||
extensions_allowlist_.insert({
|
||||
"SPV_AMD_shader_explicit_vertex_parameter",
|
||||
"SPV_AMD_shader_trinary_minmax",
|
||||
"SPV_AMD_gcn_shader",
|
||||
"SPV_KHR_shader_ballot",
|
||||
"SPV_AMD_shader_ballot",
|
||||
"SPV_AMD_gpu_shader_half_float",
|
||||
"SPV_KHR_shader_draw_parameters",
|
||||
"SPV_KHR_subgroup_vote",
|
||||
"SPV_KHR_8bit_storage",
|
||||
"SPV_KHR_16bit_storage",
|
||||
"SPV_KHR_device_group",
|
||||
"SPV_KHR_multiview",
|
||||
"SPV_NVX_multiview_per_view_attributes",
|
||||
"SPV_NV_viewport_array2",
|
||||
"SPV_NV_stereo_view_rendering",
|
||||
"SPV_NV_sample_mask_override_coverage",
|
||||
"SPV_NV_geometry_shader_passthrough",
|
||||
"SPV_AMD_texture_gather_bias_lod",
|
||||
"SPV_KHR_storage_buffer_storage_class",
|
||||
"SPV_KHR_variable_pointers",
|
||||
"SPV_AMD_gpu_shader_int16",
|
||||
"SPV_KHR_post_depth_coverage",
|
||||
"SPV_KHR_shader_atomic_counter_ops",
|
||||
"SPV_EXT_shader_stencil_export",
|
||||
"SPV_EXT_shader_viewport_index_layer",
|
||||
"SPV_AMD_shader_image_load_store_lod",
|
||||
"SPV_AMD_shader_fragment_mask",
|
||||
"SPV_EXT_fragment_fully_covered",
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
"SPV_NV_compute_shader_derivatives",
|
||||
"SPV_NV_shader_image_footprint",
|
||||
"SPV_NV_shading_rate",
|
||||
"SPV_NV_mesh_shader",
|
||||
"SPV_NV_ray_tracing",
|
||||
"SPV_KHR_ray_query",
|
||||
"SPV_EXT_fragment_invocation_density",
|
||||
"SPV_EXT_physical_storage_buffer",
|
||||
"SPV_KHR_terminate_invocation",
|
||||
"SPV_KHR_subgroup_uniform_control_flow",
|
||||
"SPV_KHR_integer_dot_product",
|
||||
"SPV_EXT_shader_image_int64",
|
||||
"SPV_KHR_non_semantic_info",
|
||||
"SPV_KHR_uniform_group_instructions",
|
||||
"SPV_KHR_fragment_shader_barycentric",
|
||||
"SPV_KHR_vulkan_memory_model",
|
||||
"SPV_NV_bindless_texture",
|
||||
});
|
||||
extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter",
|
||||
"SPV_AMD_shader_trinary_minmax",
|
||||
"SPV_AMD_gcn_shader",
|
||||
"SPV_KHR_shader_ballot",
|
||||
"SPV_AMD_shader_ballot",
|
||||
"SPV_AMD_gpu_shader_half_float",
|
||||
"SPV_KHR_shader_draw_parameters",
|
||||
"SPV_KHR_subgroup_vote",
|
||||
"SPV_KHR_8bit_storage",
|
||||
"SPV_KHR_16bit_storage",
|
||||
"SPV_KHR_device_group",
|
||||
"SPV_KHR_multiview",
|
||||
"SPV_NVX_multiview_per_view_attributes",
|
||||
"SPV_NV_viewport_array2",
|
||||
"SPV_NV_stereo_view_rendering",
|
||||
"SPV_NV_sample_mask_override_coverage",
|
||||
"SPV_NV_geometry_shader_passthrough",
|
||||
"SPV_AMD_texture_gather_bias_lod",
|
||||
"SPV_KHR_storage_buffer_storage_class",
|
||||
"SPV_KHR_variable_pointers",
|
||||
"SPV_AMD_gpu_shader_int16",
|
||||
"SPV_KHR_post_depth_coverage",
|
||||
"SPV_KHR_shader_atomic_counter_ops",
|
||||
"SPV_EXT_shader_stencil_export",
|
||||
"SPV_EXT_shader_viewport_index_layer",
|
||||
"SPV_AMD_shader_image_load_store_lod",
|
||||
"SPV_AMD_shader_fragment_mask",
|
||||
"SPV_EXT_fragment_fully_covered",
|
||||
"SPV_AMD_gpu_shader_half_float_fetch",
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_NV_shader_subgroup_partitioned",
|
||||
"SPV_EXT_descriptor_indexing",
|
||||
"SPV_NV_fragment_shader_barycentric",
|
||||
"SPV_NV_compute_shader_derivatives",
|
||||
"SPV_NV_shader_image_footprint",
|
||||
"SPV_NV_shading_rate",
|
||||
"SPV_NV_mesh_shader",
|
||||
"SPV_NV_ray_tracing",
|
||||
"SPV_KHR_ray_query",
|
||||
"SPV_EXT_fragment_invocation_density",
|
||||
"SPV_EXT_physical_storage_buffer",
|
||||
"SPV_KHR_terminate_invocation",
|
||||
"SPV_KHR_subgroup_uniform_control_flow",
|
||||
"SPV_KHR_integer_dot_product",
|
||||
"SPV_EXT_shader_image_int64",
|
||||
"SPV_KHR_non_semantic_info",
|
||||
"SPV_KHR_uniform_group_instructions",
|
||||
"SPV_KHR_fragment_shader_barycentric",
|
||||
"SPV_KHR_vulkan_memory_model",
|
||||
"SPV_NV_bindless_texture",
|
||||
"SPV_EXT_shader_atomic_float_add"});
|
||||
}
|
||||
bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
|
||||
std::vector<Instruction*> users;
|
||||
|
||||
5
3rdparty/spirv-tools/source/opt/mem_pass.cpp
vendored
5
3rdparty/spirv-tools/source/opt/mem_pass.cpp
vendored
@@ -76,6 +76,11 @@ bool MemPass::IsNonPtrAccessChain(const spv::Op opcode) const {
|
||||
bool MemPass::IsPtr(uint32_t ptrId) {
|
||||
uint32_t varId = ptrId;
|
||||
Instruction* ptrInst = get_def_use_mgr()->GetDef(varId);
|
||||
if (ptrInst->opcode() == spv::Op::OpFunction) {
|
||||
// A function is not a pointer, but it's return type could be, which will
|
||||
// erroneously lead to this function returning true later on
|
||||
return false;
|
||||
}
|
||||
while (ptrInst->opcode() == spv::Op::OpCopyObject) {
|
||||
varId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx);
|
||||
ptrInst = get_def_use_mgr()->GetDef(varId);
|
||||
|
||||
1
3rdparty/spirv-tools/source/opt/module.h
vendored
1
3rdparty/spirv-tools/source/opt/module.h
vendored
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
1
3rdparty/spirv-tools/source/opt/passes.h
vendored
1
3rdparty/spirv-tools/source/opt/passes.h
vendored
@@ -82,6 +82,7 @@
|
||||
#include "source/opt/strength_reduction_pass.h"
|
||||
#include "source/opt/strip_debug_info_pass.h"
|
||||
#include "source/opt/strip_nonsemantic_info_pass.h"
|
||||
#include "source/opt/trim_capabilities_pass.h"
|
||||
#include "source/opt/unify_const_pass.h"
|
||||
#include "source/opt/upgrade_memory_model.h"
|
||||
#include "source/opt/vector_dce.h"
|
||||
|
||||
320
3rdparty/spirv-tools/source/opt/trim_capabilities_pass.cpp
vendored
Normal file
320
3rdparty/spirv-tools/source/opt/trim_capabilities_pass.cpp
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
// Copyright (c) 2023 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/opt/trim_capabilities_pass.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "source/enum_set.h"
|
||||
#include "source/enum_string_mapping.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "source/util/string_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
namespace {
|
||||
constexpr uint32_t kVariableStorageClassIndex = 0;
|
||||
constexpr uint32_t kTypeArrayTypeIndex = 0;
|
||||
constexpr uint32_t kOpTypeScalarBitWidthIndex = 0;
|
||||
constexpr uint32_t kTypePointerTypeIdInIdx = 1;
|
||||
} // namespace
|
||||
|
||||
// ============== Begin opcode handler implementations. =======================
|
||||
//
|
||||
// Adding support for a new capability should only require adding a new handler,
|
||||
// and updating the
|
||||
// kSupportedCapabilities/kUntouchableCapabilities/kFordiddenCapabilities lists.
|
||||
//
|
||||
// Handler names follow the following convention:
|
||||
// Handler_<Opcode>_<Capability>()
|
||||
|
||||
static std::optional<spv::Capability> Handler_OpVariable_StorageInputOutput16(
|
||||
const Instruction* instruction) {
|
||||
assert(instruction->opcode() == spv::Op::OpVariable &&
|
||||
"This handler only support OpVariable opcodes.");
|
||||
|
||||
// This capability is only required if the variable as an Input/Output storage
|
||||
// class.
|
||||
spv::StorageClass storage_class = spv::StorageClass(
|
||||
instruction->GetSingleWordInOperand(kVariableStorageClassIndex));
|
||||
if (storage_class != spv::StorageClass::Input &&
|
||||
storage_class != spv::StorageClass::Output) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// This capability is only required if the type involves a 16-bit component.
|
||||
// Quick check: are 16-bit types allowed?
|
||||
const CapabilitySet& capabilities =
|
||||
instruction->context()->get_feature_mgr()->GetCapabilities();
|
||||
if (!capabilities.contains(spv::Capability::Float16) &&
|
||||
!capabilities.contains(spv::Capability::Int16)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// We need to walk the type definition.
|
||||
std::queue<uint32_t> instructions_to_visit;
|
||||
instructions_to_visit.push(instruction->type_id());
|
||||
const auto* def_use_mgr = instruction->context()->get_def_use_mgr();
|
||||
while (!instructions_to_visit.empty()) {
|
||||
const Instruction* item =
|
||||
def_use_mgr->GetDef(instructions_to_visit.front());
|
||||
instructions_to_visit.pop();
|
||||
|
||||
if (item->opcode() == spv::Op::OpTypePointer) {
|
||||
instructions_to_visit.push(
|
||||
item->GetSingleWordInOperand(kTypePointerTypeIdInIdx));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->opcode() == spv::Op::OpTypeMatrix ||
|
||||
item->opcode() == spv::Op::OpTypeVector ||
|
||||
item->opcode() == spv::Op::OpTypeArray ||
|
||||
item->opcode() == spv::Op::OpTypeRuntimeArray) {
|
||||
instructions_to_visit.push(
|
||||
item->GetSingleWordInOperand(kTypeArrayTypeIndex));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->opcode() == spv::Op::OpTypeStruct) {
|
||||
item->ForEachInOperand([&instructions_to_visit](const uint32_t* op_id) {
|
||||
instructions_to_visit.push(*op_id);
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->opcode() != spv::Op::OpTypeInt &&
|
||||
item->opcode() != spv::Op::OpTypeFloat) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16) {
|
||||
return spv::Capability::StorageInputOutput16;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Opcode of interest to determine capabilities requirements.
|
||||
constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 1> kOpcodeHandlers{{
|
||||
{spv::Op::OpVariable, Handler_OpVariable_StorageInputOutput16},
|
||||
}};
|
||||
|
||||
// ============== End opcode handler implementations. =======================
|
||||
|
||||
namespace {
|
||||
ExtensionSet getExtensionsRelatedTo(const CapabilitySet& capabilities,
|
||||
const AssemblyGrammar& grammar) {
|
||||
ExtensionSet output;
|
||||
const spv_operand_desc_t* desc = nullptr;
|
||||
for (auto capability : capabilities) {
|
||||
if (SPV_SUCCESS != grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
|
||||
static_cast<uint32_t>(capability),
|
||||
&desc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < desc->numExtensions; ++i) {
|
||||
output.insert(desc->extensions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TrimCapabilitiesPass::TrimCapabilitiesPass()
|
||||
: supportedCapabilities_(
|
||||
TrimCapabilitiesPass::kSupportedCapabilities.cbegin(),
|
||||
TrimCapabilitiesPass::kSupportedCapabilities.cend()),
|
||||
forbiddenCapabilities_(
|
||||
TrimCapabilitiesPass::kForbiddenCapabilities.cbegin(),
|
||||
TrimCapabilitiesPass::kForbiddenCapabilities.cend()),
|
||||
untouchableCapabilities_(
|
||||
TrimCapabilitiesPass::kUntouchableCapabilities.cbegin(),
|
||||
TrimCapabilitiesPass::kUntouchableCapabilities.cend()),
|
||||
opcodeHandlers_(kOpcodeHandlers.cbegin(), kOpcodeHandlers.cend()) {}
|
||||
|
||||
void TrimCapabilitiesPass::addInstructionRequirements(
|
||||
Instruction* instruction, CapabilitySet* capabilities,
|
||||
ExtensionSet* extensions) const {
|
||||
// Ignoring OpCapability instructions.
|
||||
if (instruction->opcode() == spv::Op::OpCapability) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First case: the opcode is itself gated by a capability.
|
||||
{
|
||||
const spv_opcode_desc_t* desc = {};
|
||||
auto result =
|
||||
context()->grammar().lookupOpcode(instruction->opcode(), &desc);
|
||||
if (result == SPV_SUCCESS) {
|
||||
addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities,
|
||||
capabilities);
|
||||
if (desc->minVersion <=
|
||||
spvVersionForTargetEnv(context()->GetTargetEnv())) {
|
||||
extensions->insert(desc->extensions,
|
||||
desc->extensions + desc->numExtensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second case: one of the opcode operand is gated by a capability.
|
||||
const uint32_t operandCount = instruction->NumOperands();
|
||||
for (uint32_t i = 0; i < operandCount; i++) {
|
||||
const auto& operand = instruction->GetOperand(i);
|
||||
// No supported capability relies on a 2+-word operand.
|
||||
if (operand.words.size() != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// No supported capability relies on a literal string operand.
|
||||
if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const spv_operand_desc_t* desc = {};
|
||||
auto result = context()->grammar().lookupOperand(operand.type,
|
||||
operand.words[0], &desc);
|
||||
if (result != SPV_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities,
|
||||
capabilities);
|
||||
if (desc->minVersion <= spvVersionForTargetEnv(context()->GetTargetEnv())) {
|
||||
extensions->insert(desc->extensions,
|
||||
desc->extensions + desc->numExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
// Last case: some complex logic needs to be run to determine capabilities.
|
||||
auto[begin, end] = opcodeHandlers_.equal_range(instruction->opcode());
|
||||
for (auto it = begin; it != end; it++) {
|
||||
const OpcodeHandler handler = it->second;
|
||||
auto result = handler(instruction);
|
||||
if (result.has_value()) {
|
||||
capabilities->insert(*result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<CapabilitySet, ExtensionSet>
|
||||
TrimCapabilitiesPass::DetermineRequiredCapabilitiesAndExtensions() const {
|
||||
CapabilitySet required_capabilities;
|
||||
ExtensionSet required_extensions;
|
||||
|
||||
get_module()->ForEachInst([&](Instruction* instruction) {
|
||||
addInstructionRequirements(instruction, &required_capabilities,
|
||||
&required_extensions);
|
||||
});
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
// Debug only. We check the outputted required capabilities against the
|
||||
// supported capabilities list. The supported capabilities list is useful for
|
||||
// API users to quickly determine if they can use the pass or not. But this
|
||||
// list has to remain up-to-date with the pass code. If we can detect a
|
||||
// capability as required, but it's not listed, it means the list is
|
||||
// out-of-sync. This method is not ideal, but should cover most cases.
|
||||
{
|
||||
for (auto capability : required_capabilities) {
|
||||
assert(supportedCapabilities_.contains(capability) &&
|
||||
"Module is using a capability that is not listed as supported.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return std::make_pair(std::move(required_capabilities),
|
||||
std::move(required_extensions));
|
||||
}
|
||||
|
||||
Pass::Status TrimCapabilitiesPass::TrimUnrequiredCapabilities(
|
||||
const CapabilitySet& required_capabilities) const {
|
||||
const FeatureManager* feature_manager = context()->get_feature_mgr();
|
||||
CapabilitySet capabilities_to_trim;
|
||||
for (auto capability : feature_manager->GetCapabilities()) {
|
||||
// Forbidden capability completely prevents trimming. Early exit.
|
||||
if (forbiddenCapabilities_.contains(capability)) {
|
||||
return Pass::Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
// Some capabilities cannot be safely removed. Leaving them untouched.
|
||||
if (untouchableCapabilities_.contains(capability)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the capability is unsupported, don't trim it.
|
||||
if (!supportedCapabilities_.contains(capability)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (required_capabilities.contains(capability)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
capabilities_to_trim.insert(capability);
|
||||
}
|
||||
|
||||
for (auto capability : capabilities_to_trim) {
|
||||
context()->RemoveCapability(capability);
|
||||
}
|
||||
|
||||
return capabilities_to_trim.size() == 0 ? Pass::Status::SuccessWithoutChange
|
||||
: Pass::Status::SuccessWithChange;
|
||||
}
|
||||
|
||||
Pass::Status TrimCapabilitiesPass::TrimUnrequiredExtensions(
|
||||
const ExtensionSet& required_extensions) const {
|
||||
const auto supported_extensions =
|
||||
getExtensionsRelatedTo(supportedCapabilities_, context()->grammar());
|
||||
|
||||
bool modified_module = false;
|
||||
for (auto extension : supported_extensions) {
|
||||
if (!required_extensions.contains(extension)) {
|
||||
modified_module = true;
|
||||
context()->RemoveExtension(extension);
|
||||
}
|
||||
}
|
||||
|
||||
return modified_module ? Pass::Status::SuccessWithChange
|
||||
: Pass::Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
Pass::Status TrimCapabilitiesPass::Process() {
|
||||
auto[required_capabilities, required_extensions] =
|
||||
DetermineRequiredCapabilitiesAndExtensions();
|
||||
|
||||
Pass::Status status = TrimUnrequiredCapabilities(required_capabilities);
|
||||
// If no capabilities were removed, we have no extension to trim.
|
||||
// Note: this is true because this pass only removes unused extensions caused
|
||||
// by unused capabilities.
|
||||
// This is not an extension trimming pass.
|
||||
if (status == Pass::Status::SuccessWithoutChange) {
|
||||
return status;
|
||||
}
|
||||
return TrimUnrequiredExtensions(required_extensions);
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
151
3rdparty/spirv-tools/source/opt/trim_capabilities_pass.h
vendored
Normal file
151
3rdparty/spirv-tools/source/opt/trim_capabilities_pass.h
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright (c) 2023 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_OPT_TRIM_CAPABILITIES_PASS_H_
|
||||
#define SOURCE_OPT_TRIM_CAPABILITIES_PASS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/enum_set.h"
|
||||
#include "source/extensions.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/opt/module.h"
|
||||
#include "source/opt/pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// This is required for NDK build. The unordered_set/unordered_map
|
||||
// implementation don't work with class enums.
|
||||
struct ClassEnumHash {
|
||||
std::size_t operator()(spv::Capability value) const {
|
||||
using StoringType = typename std::underlying_type_t<spv::Capability>;
|
||||
return std::hash<StoringType>{}(static_cast<StoringType>(value));
|
||||
}
|
||||
|
||||
std::size_t operator()(spv::Op value) const {
|
||||
using StoringType = typename std::underlying_type_t<spv::Op>;
|
||||
return std::hash<StoringType>{}(static_cast<StoringType>(value));
|
||||
}
|
||||
};
|
||||
|
||||
// An opcode handler is a function which, given an instruction, returns either
|
||||
// the required capability, or nothing.
|
||||
// Each handler checks one case for a capability requirement.
|
||||
//
|
||||
// Example:
|
||||
// - `OpTypeImage` can have operand `A` operand which requires capability 1
|
||||
// - `OpTypeImage` can also have operand `B` which requires capability 2.
|
||||
// -> We have 2 handlers: `Handler_OpTypeImage_1` and
|
||||
// `Handler_OpTypeImage_2`.
|
||||
using OpcodeHandler =
|
||||
std::optional<spv::Capability> (*)(const Instruction* instruction);
|
||||
|
||||
// This pass tried to remove superfluous capabilities declared in the module.
|
||||
// - If all the capabilities listed by an extension are removed, the extension
|
||||
// is also trimmed.
|
||||
// - If the module countains any capability listed in `kForbiddenCapabilities`,
|
||||
// the module is left untouched.
|
||||
// - No capabilities listed in `kUntouchableCapabilities` are trimmed, even when
|
||||
// not used.
|
||||
// - Only capabilitied listed in `kSupportedCapabilities` are supported.
|
||||
// - If the module contains unsupported capabilities, results might be
|
||||
// incorrect.
|
||||
class TrimCapabilitiesPass : public Pass {
|
||||
private:
|
||||
// All the capabilities supported by this optimization pass. If your module
|
||||
// contains unsupported instruction, the pass could yield bad results.
|
||||
static constexpr std::array kSupportedCapabilities{
|
||||
// clang-format off
|
||||
spv::Capability::Groups,
|
||||
spv::Capability::Linkage,
|
||||
spv::Capability::MinLod,
|
||||
spv::Capability::Shader,
|
||||
spv::Capability::ShaderClockKHR,
|
||||
spv::Capability::StorageInputOutput16
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// Those capabilities disable all transformation of the module.
|
||||
static constexpr std::array kForbiddenCapabilities{
|
||||
spv::Capability::Linkage,
|
||||
};
|
||||
|
||||
// Those capabilities are never removed from a module because we cannot
|
||||
// guess from the SPIR-V only if they are required or not.
|
||||
static constexpr std::array kUntouchableCapabilities{
|
||||
spv::Capability::Shader,
|
||||
};
|
||||
|
||||
public:
|
||||
TrimCapabilitiesPass();
|
||||
TrimCapabilitiesPass(const TrimCapabilitiesPass&) = delete;
|
||||
TrimCapabilitiesPass(TrimCapabilitiesPass&&) = delete;
|
||||
|
||||
private:
|
||||
// Inserts every capability in `capabilities[capabilityCount]` supported by
|
||||
// this pass into `output`.
|
||||
inline void addSupportedCapabilitiesToSet(
|
||||
uint32_t capabilityCount, const spv::Capability* const capabilities,
|
||||
CapabilitySet* output) const {
|
||||
for (uint32_t i = 0; i < capabilityCount; ++i) {
|
||||
if (supportedCapabilities_.contains(capabilities[i])) {
|
||||
output->insert(capabilities[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Given an `instruction`, determines the capabilities and extension it
|
||||
// requires, and output them in `capabilities` and `extensions`. The returned
|
||||
// capabilities form a subset of kSupportedCapabilities.
|
||||
void addInstructionRequirements(Instruction* instruction,
|
||||
CapabilitySet* capabilities,
|
||||
ExtensionSet* extensions) const;
|
||||
|
||||
// Returns the list of required capabilities and extensions for the module.
|
||||
// The returned capabilities form a subset of kSupportedCapabilities.
|
||||
std::pair<CapabilitySet, ExtensionSet>
|
||||
DetermineRequiredCapabilitiesAndExtensions() const;
|
||||
|
||||
// Trims capabilities not listed in `required_capabilities` if possible.
|
||||
// Returns whether or not the module was modified.
|
||||
Pass::Status TrimUnrequiredCapabilities(
|
||||
const CapabilitySet& required_capabilities) const;
|
||||
|
||||
// Trims extensions not listed in `required_extensions` if supported by this
|
||||
// pass. An extensions is considered supported as soon as one capability this
|
||||
// pass support requires it.
|
||||
Pass::Status TrimUnrequiredExtensions(
|
||||
const ExtensionSet& required_extensions) const;
|
||||
|
||||
public:
|
||||
const char* name() const override { return "trim-capabilities"; }
|
||||
Status Process() override;
|
||||
|
||||
private:
|
||||
const CapabilitySet supportedCapabilities_;
|
||||
const CapabilitySet forbiddenCapabilities_;
|
||||
const CapabilitySet untouchableCapabilities_;
|
||||
const std::unordered_multimap<spv::Op, OpcodeHandler, ClassEnumHash>
|
||||
opcodeHandlers_;
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
#endif // SOURCE_OPT_TRIM_CAPABILITIES_H_
|
||||
@@ -24,6 +24,7 @@ namespace spvtools {
|
||||
void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst,
|
||||
const spv_parsed_operand_t& operand) {
|
||||
if (operand.type != SPV_OPERAND_TYPE_LITERAL_INTEGER &&
|
||||
operand.type != SPV_OPERAND_TYPE_LITERAL_FLOAT &&
|
||||
operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER &&
|
||||
operand.type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER &&
|
||||
operand.type != SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER)
|
||||
|
||||
11
3rdparty/spirv-tools/source/text.cpp
vendored
11
3rdparty/spirv-tools/source/text.cpp
vendored
@@ -312,6 +312,17 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
|
||||
// The current operand is a 32-bit float.
|
||||
// That's just how the grammar works.
|
||||
spvtools::IdType expected_type = {
|
||||
32, false, spvtools::IdTypeClass::kScalarFloatType};
|
||||
if (auto error = context->binaryEncodeNumericLiteral(
|
||||
textValue, error_code_for_literals, expected_type, pInst)) {
|
||||
return error;
|
||||
}
|
||||
} break;
|
||||
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
|
||||
// This is a context-independent literal number which can be a 32-bit
|
||||
// number of floating point value.
|
||||
|
||||
Reference in New Issue
Block a user