mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-17 20:52:36 +01:00
Updated spirv-tools.
This commit is contained in:
committed by
Branimir Karadžić
parent
c02ebda27d
commit
a3df232816
@@ -1 +1 @@
|
||||
"v2025.4", "SPIRV-Tools v2025.4 v2025.4-28-g8b4ee452"
|
||||
"v2025.5", "SPIRV-Tools v2025.5 v2025.4-64-gd2a11ec9"
|
||||
|
||||
17996
3rdparty/spirv-tools/include/generated/core_tables_body.inc
vendored
17996
3rdparty/spirv-tools/include/generated/core_tables_body.inc
vendored
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,26 @@ enum class PrintingClass : uint32_t {
|
||||
};
|
||||
|
||||
enum Extension : uint32_t {
|
||||
kSPV_ALTERA_arbitrary_precision_fixed_point,
|
||||
kSPV_ALTERA_arbitrary_precision_floating_point,
|
||||
kSPV_ALTERA_arbitrary_precision_integers,
|
||||
kSPV_ALTERA_blocking_pipes,
|
||||
kSPV_ALTERA_fpga_argument_interfaces,
|
||||
kSPV_ALTERA_fpga_buffer_location,
|
||||
kSPV_ALTERA_fpga_cluster_attributes,
|
||||
kSPV_ALTERA_fpga_dsp_control,
|
||||
kSPV_ALTERA_fpga_invocation_pipelining_attributes,
|
||||
kSPV_ALTERA_fpga_latency_control,
|
||||
kSPV_ALTERA_fpga_loop_controls,
|
||||
kSPV_ALTERA_fpga_memory_accesses,
|
||||
kSPV_ALTERA_fpga_memory_attributes,
|
||||
kSPV_ALTERA_fpga_reg,
|
||||
kSPV_ALTERA_global_variable_fpga_decorations,
|
||||
kSPV_ALTERA_io_pipes,
|
||||
kSPV_ALTERA_loop_fuse,
|
||||
kSPV_ALTERA_runtime_aligned,
|
||||
kSPV_ALTERA_task_sequence,
|
||||
kSPV_ALTERA_usm_storage_classes,
|
||||
kSPV_AMDX_shader_enqueue,
|
||||
kSPV_AMD_gcn_shader,
|
||||
kSPV_AMD_gpu_shader_half_float,
|
||||
@@ -59,10 +79,12 @@ enum Extension : uint32_t {
|
||||
kSPV_EXT_physical_storage_buffer,
|
||||
kSPV_EXT_relaxed_printf_string_address_space,
|
||||
kSPV_EXT_replicated_composites,
|
||||
kSPV_EXT_shader_64bit_indexing,
|
||||
kSPV_EXT_shader_atomic_float16_add,
|
||||
kSPV_EXT_shader_atomic_float_add,
|
||||
kSPV_EXT_shader_atomic_float_min_max,
|
||||
kSPV_EXT_shader_image_int64,
|
||||
kSPV_EXT_shader_invocation_reorder,
|
||||
kSPV_EXT_shader_stencil_export,
|
||||
kSPV_EXT_shader_tile_image,
|
||||
kSPV_EXT_shader_viewport_index_layer,
|
||||
|
||||
1
3rdparty/spirv-tools/source/opcode.cpp
vendored
1
3rdparty/spirv-tools/source/opcode.cpp
vendored
@@ -267,6 +267,7 @@ int32_t spvOpcodeGeneratesType(spv::Op op) {
|
||||
// spv::Op::OpTypeAccelerationStructureNV
|
||||
case spv::Op::OpTypeRayQueryKHR:
|
||||
case spv::Op::OpTypeHitObjectNV:
|
||||
case spv::Op::OpTypeHitObjectEXT:
|
||||
case spv::Op::OpTypeUntypedPointerKHR:
|
||||
case spv::Op::OpTypeNodePayloadArrayAMDX:
|
||||
case spv::Op::OpTypeTensorLayoutNV:
|
||||
|
||||
@@ -305,7 +305,7 @@ Pass::Status AggressiveDCEPass::ProcessDebugInformation(
|
||||
NonSemanticShaderDebugInfo100DebugValue) {
|
||||
uint32_t id = inst->GetSingleWordInOperand(kDebugValueValue);
|
||||
auto def = get_def_use_mgr()->GetDef(id);
|
||||
if (!live_insts_.Set(def->unique_id())) {
|
||||
if (!IsLive(def)) {
|
||||
AddToWorklist(inst);
|
||||
uint32_t undef_id = Type2Undef(def->type_id());
|
||||
if (undef_id == 0) {
|
||||
@@ -1123,6 +1123,7 @@ void AggressiveDCEPass::InitExtensions() {
|
||||
"SPV_NV_shader_invocation_reorder",
|
||||
"SPV_NV_cluster_acceleration_structure",
|
||||
"SPV_NV_linear_swept_spheres",
|
||||
"SPV_KHR_maximal_reconvergence",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
181
3rdparty/spirv-tools/source/opt/amd_ext_to_khr.cpp
vendored
181
3rdparty/spirv-tools/source/opt/amd_ext_to_khr.cpp
vendored
@@ -76,6 +76,7 @@ bool ReplaceTrinaryMinMax(IRContext* ctx, Instruction* inst,
|
||||
|
||||
Instruction* temp = ir_builder.AddNaryExtendedInstruction(
|
||||
inst->type_id(), glsl405_ext_inst_id, opcode, {op1, op2});
|
||||
if (temp == nullptr) return false;
|
||||
|
||||
Instruction::OperandList new_operands;
|
||||
new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}});
|
||||
@@ -114,9 +115,12 @@ bool ReplaceTrinaryMid(IRContext* ctx, Instruction* inst,
|
||||
Instruction* min = ir_builder.AddNaryExtendedInstruction(
|
||||
inst->type_id(), glsl405_ext_inst_id, static_cast<uint32_t>(min_opcode),
|
||||
{op2, op3});
|
||||
if (min == nullptr) return false;
|
||||
|
||||
Instruction* max = ir_builder.AddNaryExtendedInstruction(
|
||||
inst->type_id(), glsl405_ext_inst_id, static_cast<uint32_t>(max_opcode),
|
||||
{op2, op3});
|
||||
if (max == nullptr) return false;
|
||||
|
||||
Instruction::OperandList new_operands;
|
||||
new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}});
|
||||
@@ -226,16 +230,20 @@ bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
|
||||
// Get the subgroup invocation id.
|
||||
uint32_t var_id = ctx->GetBuiltinInputVarId(
|
||||
uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
|
||||
assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
|
||||
if (var_id == 0) return false;
|
||||
Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
|
||||
if (var_inst == nullptr) return false;
|
||||
Instruction* var_ptr_type =
|
||||
ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
|
||||
if (var_ptr_type == nullptr) return false;
|
||||
uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
|
||||
if (uint_type_id == 0) return false;
|
||||
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
|
||||
if (id == nullptr) return false;
|
||||
|
||||
uint32_t quad_mask = ir_builder.GetUintConstantId(3);
|
||||
if (quad_mask == 0) return false;
|
||||
|
||||
// This gives the offset in the group of 4 of this invocation.
|
||||
Instruction* quad_idx = ir_builder.AddBinaryOp(
|
||||
@@ -262,26 +270,41 @@ bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
|
||||
|
||||
// Do the group operations
|
||||
uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
|
||||
if (uint_max_id == 0) return false;
|
||||
uint32_t subgroup_scope =
|
||||
ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
|
||||
if (subgroup_scope == 0) return false;
|
||||
const auto* vec_type = type_mgr->GetUIntVectorType(4);
|
||||
if (vec_type == nullptr) return false;
|
||||
const auto* ballot_value_const = const_mgr->GetConstant(
|
||||
type_mgr->GetUIntVectorType(4),
|
||||
{uint_max_id, uint_max_id, uint_max_id, uint_max_id});
|
||||
vec_type, {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
|
||||
if (ballot_value_const == nullptr) return false;
|
||||
Instruction* ballot_value =
|
||||
const_mgr->GetDefiningInstruction(ballot_value_const);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (ballot_value == nullptr) return false;
|
||||
uint32_t bool_type_id = type_mgr->GetBoolTypeId();
|
||||
if (bool_type_id == 0) return false;
|
||||
Instruction* is_active = ir_builder.AddNaryOp(
|
||||
type_mgr->GetBoolTypeId(), spv::Op::OpGroupNonUniformBallotBitExtract,
|
||||
bool_type_id, spv::Op::OpGroupNonUniformBallotBitExtract,
|
||||
{subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (is_active == nullptr) return false;
|
||||
Instruction* shuffle =
|
||||
ir_builder.AddNaryOp(inst->type_id(), spv::Op::OpGroupNonUniformShuffle,
|
||||
{subgroup_scope, data_id, target_inv->result_id()});
|
||||
if (shuffle == nullptr) return false;
|
||||
|
||||
// Create the null constant to use in the select.
|
||||
const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()),
|
||||
std::vector<uint32_t>());
|
||||
const auto* result_type = type_mgr->GetType(inst->type_id());
|
||||
if (result_type == nullptr) return false;
|
||||
const auto* null =
|
||||
const_mgr->GetConstant(result_type, std::vector<uint32_t>());
|
||||
if (null == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
|
||||
if (null_inst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the select.
|
||||
inst->SetOpcode(spv::Op::OpSelect);
|
||||
@@ -346,30 +369,38 @@ bool ReplaceSwizzleInvocationsMasked(
|
||||
uint32_t data_id = inst->GetSingleWordInOperand(2);
|
||||
|
||||
Instruction* mask_inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(3));
|
||||
if (mask_inst == nullptr) return false;
|
||||
assert(mask_inst->opcode() == spv::Op::OpConstantComposite &&
|
||||
"The mask is suppose to be a vector constant.");
|
||||
assert(mask_inst->NumInOperands() == 3 &&
|
||||
"The mask is suppose to have 3 components.");
|
||||
|
||||
uint32_t uint_x = mask_inst->GetSingleWordInOperand(0);
|
||||
if (uint_x == 0) return false;
|
||||
uint32_t uint_y = mask_inst->GetSingleWordInOperand(1);
|
||||
if (uint_y == 0) return false;
|
||||
uint32_t uint_z = mask_inst->GetSingleWordInOperand(2);
|
||||
if (uint_z == 0) return false;
|
||||
|
||||
// Get the subgroup invocation id.
|
||||
uint32_t var_id = ctx->GetBuiltinInputVarId(
|
||||
uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
|
||||
if (var_id == 0) return false;
|
||||
ctx->AddExtension("SPV_KHR_shader_ballot");
|
||||
assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
|
||||
Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
|
||||
if (var_inst == nullptr) return false;
|
||||
Instruction* var_ptr_type =
|
||||
ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
|
||||
if (var_ptr_type == nullptr) return false;
|
||||
uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
|
||||
if (uint_type_id == 0) return false;
|
||||
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
|
||||
if (id == nullptr) return false;
|
||||
|
||||
// Do the bitwise operations.
|
||||
uint32_t mask_extended = ir_builder.GetUintConstantId(0xFFFFFFE0);
|
||||
if (mask_extended == 0) return false;
|
||||
Instruction* and_mask = ir_builder.AddBinaryOp(
|
||||
uint_type_id, spv::Op::OpBitwiseOr, uint_x, mask_extended);
|
||||
if (and_mask == nullptr) return false;
|
||||
@@ -386,26 +417,37 @@ bool ReplaceSwizzleInvocationsMasked(
|
||||
|
||||
// Do the group operations
|
||||
uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
|
||||
if (uint_max_id == 0) return false;
|
||||
uint32_t subgroup_scope =
|
||||
ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
|
||||
if (subgroup_scope == 0) return false;
|
||||
const auto* vec_type = type_mgr->GetUIntVectorType(4);
|
||||
if (vec_type == nullptr) return false;
|
||||
const auto* ballot_value_const = const_mgr->GetConstant(
|
||||
type_mgr->GetUIntVectorType(4),
|
||||
{uint_max_id, uint_max_id, uint_max_id, uint_max_id});
|
||||
vec_type, {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
|
||||
if (ballot_value_const == nullptr) return false;
|
||||
Instruction* ballot_value =
|
||||
const_mgr->GetDefiningInstruction(ballot_value_const);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (ballot_value == nullptr) return false;
|
||||
uint32_t bool_type_id = type_mgr->GetBoolTypeId();
|
||||
if (bool_type_id == 0) return false;
|
||||
Instruction* is_active = ir_builder.AddNaryOp(
|
||||
type_mgr->GetBoolTypeId(), spv::Op::OpGroupNonUniformBallotBitExtract,
|
||||
bool_type_id, spv::Op::OpGroupNonUniformBallotBitExtract,
|
||||
{subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (is_active == nullptr) return false;
|
||||
Instruction* shuffle =
|
||||
ir_builder.AddNaryOp(inst->type_id(), spv::Op::OpGroupNonUniformShuffle,
|
||||
{subgroup_scope, data_id, target_inv->result_id()});
|
||||
if (shuffle == nullptr) return false;
|
||||
|
||||
// Create the null constant to use in the select.
|
||||
const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()),
|
||||
std::vector<uint32_t>());
|
||||
const auto* result_type = type_mgr->GetType(inst->type_id());
|
||||
if (result_type == nullptr) return false;
|
||||
const auto* null =
|
||||
const_mgr->GetConstant(result_type, std::vector<uint32_t>());
|
||||
if (null == nullptr) return false;
|
||||
Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
|
||||
if (null_inst == nullptr) return false;
|
||||
|
||||
// Build the select.
|
||||
inst->SetOpcode(spv::Op::OpSelect);
|
||||
@@ -439,21 +481,24 @@ bool ReplaceWriteInvocation(IRContext* ctx, Instruction* inst,
|
||||
const std::vector<const analysis::Constant*>&) {
|
||||
uint32_t var_id = ctx->GetBuiltinInputVarId(
|
||||
uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
|
||||
ctx->AddCapability(spv::Capability::SubgroupBallotKHR);
|
||||
ctx->AddExtension("SPV_KHR_shader_ballot");
|
||||
assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
|
||||
if (var_id == 0) return false;
|
||||
Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
|
||||
if (var_inst == nullptr) return false;
|
||||
Instruction* var_ptr_type =
|
||||
ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
|
||||
if (var_ptr_type == nullptr) return false;
|
||||
ctx->AddCapability(spv::Capability::SubgroupBallotKHR);
|
||||
ctx->AddExtension("SPV_KHR_shader_ballot");
|
||||
|
||||
InstructionBuilder ir_builder(
|
||||
ctx, inst,
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* t =
|
||||
ir_builder.AddLoad(var_ptr_type->GetSingleWordInOperand(1), var_id);
|
||||
if (t == nullptr) return false;
|
||||
analysis::Bool bool_type;
|
||||
uint32_t bool_type_id = ctx->get_type_mgr()->GetTypeInstruction(&bool_type);
|
||||
if (bool_type_id == 0) return false;
|
||||
Instruction* cmp =
|
||||
ir_builder.AddBinaryOp(bool_type_id, spv::Op::OpIEqual, t->result_id(),
|
||||
inst->GetSingleWordInOperand(4));
|
||||
@@ -500,7 +545,8 @@ bool ReplaceMbcnt(IRContext* context, Instruction* inst,
|
||||
|
||||
uint32_t var_id =
|
||||
context->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::SubgroupLtMask));
|
||||
assert(var_id != 0 && "Could not get SubgroupLtMask variable.");
|
||||
if (var_id == 0) return false;
|
||||
|
||||
context->AddCapability(spv::Capability::GroupNonUniformBallot);
|
||||
Instruction* var_inst = def_use_mgr->GetDef(var_id);
|
||||
Instruction* var_ptr_type = def_use_mgr->GetDef(var_inst->type_id());
|
||||
@@ -513,6 +559,7 @@ bool ReplaceMbcnt(IRContext* context, Instruction* inst,
|
||||
analysis::Vector temp_type(GetUIntType(context), 2);
|
||||
const analysis::Type* shuffle_type =
|
||||
context->get_type_mgr()->GetRegisteredType(&temp_type);
|
||||
if (shuffle_type == nullptr) return false;
|
||||
uint32_t shuffle_type_id = type_mgr->GetTypeInstruction(shuffle_type);
|
||||
|
||||
uint32_t mask_id = inst->GetSingleWordInOperand(2);
|
||||
@@ -526,10 +573,13 @@ bool ReplaceMbcnt(IRContext* context, Instruction* inst,
|
||||
context, inst,
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
Instruction* load = ir_builder.AddLoad(var_type->result_id(), var_id);
|
||||
if (load == nullptr) return false;
|
||||
Instruction* shuffle = ir_builder.AddVectorShuffle(
|
||||
shuffle_type_id, load->result_id(), load->result_id(), {0, 1});
|
||||
if (shuffle == nullptr) return false;
|
||||
Instruction* bitcast = ir_builder.AddUnaryOp(
|
||||
mask_inst->type_id(), spv::Op::OpBitcast, shuffle->result_id());
|
||||
if (bitcast == nullptr) return false;
|
||||
Instruction* t =
|
||||
ir_builder.AddBinaryOp(mask_inst->type_id(), spv::Op::OpBitwiseAnd,
|
||||
bitcast->result_id(), mask_id);
|
||||
@@ -588,9 +638,13 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
|
||||
analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
|
||||
|
||||
uint32_t float_type_id = type_mgr->GetFloatTypeId();
|
||||
if (float_type_id == 0) return false;
|
||||
const analysis::Type* v2_float_type = type_mgr->GetFloatVectorType(2);
|
||||
if (v2_float_type == nullptr) return false;
|
||||
uint32_t v2_float_type_id = type_mgr->GetId(v2_float_type);
|
||||
if (v2_float_type_id == 0) return false;
|
||||
uint32_t bool_id = type_mgr->GetBoolTypeId();
|
||||
if (bool_id == 0) return false;
|
||||
|
||||
InstructionBuilder ir_builder(
|
||||
ctx, inst,
|
||||
@@ -604,23 +658,29 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
|
||||
glsl405_ext_inst_id =
|
||||
ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
|
||||
}
|
||||
if (glsl405_ext_inst_id == 0) return false;
|
||||
|
||||
// Get the constants that will be used.
|
||||
uint32_t f0_const_id = const_mgr->GetFloatConstId(0.0);
|
||||
if (f0_const_id == 0) return false;
|
||||
uint32_t f2_const_id = const_mgr->GetFloatConstId(2.0);
|
||||
if (f2_const_id == 0) return false;
|
||||
uint32_t f0_5_const_id = const_mgr->GetFloatConstId(0.5);
|
||||
if (f0_5_const_id == 0) return false;
|
||||
const analysis::Constant* vec_const =
|
||||
const_mgr->GetConstant(v2_float_type, {f0_5_const_id, f0_5_const_id});
|
||||
uint32_t vec_const_id =
|
||||
const_mgr->GetDefiningInstruction(vec_const)->result_id();
|
||||
if (vec_const == nullptr) return false;
|
||||
Instruction* vec_const_inst = const_mgr->GetDefiningInstruction(vec_const);
|
||||
if (vec_const_inst == nullptr) return false;
|
||||
uint32_t vec_const_id = vec_const_inst->result_id();
|
||||
|
||||
// Extract the input values.
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0});
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (x == nullptr) return false;
|
||||
Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1});
|
||||
// TODO(1-841): Handle id overflow.
|
||||
if (y == nullptr) return false;
|
||||
Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2});
|
||||
if (z == nullptr) return false;
|
||||
|
||||
// Negate the input values.
|
||||
Instruction* nx =
|
||||
@@ -629,14 +689,20 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
|
||||
ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, y->result_id());
|
||||
Instruction* nz =
|
||||
ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, z->result_id());
|
||||
if (nx == nullptr) return false;
|
||||
if (ny == nullptr) return false;
|
||||
if (nz == nullptr) return false;
|
||||
|
||||
// Get the abolsute values of the inputs.
|
||||
Instruction* ax = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()});
|
||||
if (ax == nullptr) return false;
|
||||
Instruction* ay = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()});
|
||||
if (ay == nullptr) return false;
|
||||
Instruction* az = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
|
||||
if (az == nullptr) return false;
|
||||
|
||||
// Find which values are negative. Used in later computations.
|
||||
Instruction* is_z_neg = ir_builder.AddBinaryOp(
|
||||
@@ -653,9 +719,11 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
|
||||
Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
|
||||
{ax->result_id(), ay->result_id()});
|
||||
if (amax_x_y == nullptr) return false;
|
||||
Instruction* amax = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
|
||||
{az->result_id(), amax_x_y->result_id()});
|
||||
if (amax == nullptr) return false;
|
||||
Instruction* cubema = ir_builder.AddBinaryOp(float_type_id, spv::Op::OpFMul,
|
||||
f2_const_id, amax->result_id());
|
||||
if (cubema == nullptr) return false;
|
||||
@@ -667,6 +735,7 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
|
||||
if (is_z_max == nullptr) return false;
|
||||
Instruction* not_is_z_max = ir_builder.AddUnaryOp(
|
||||
bool_id, spv::Op::OpLogicalNot, is_z_max->result_id());
|
||||
if (not_is_z_max == nullptr) return false;
|
||||
Instruction* y_gr_x =
|
||||
ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
|
||||
ay->result_id(), ax->result_id());
|
||||
@@ -677,35 +746,37 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
|
||||
if (is_y_max == nullptr) return false;
|
||||
|
||||
// Select the correct value for cubesc.
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* cubesc_case_1 = ir_builder.AddSelect(
|
||||
float_type_id, is_z_neg->result_id(), nx->result_id(), x->result_id());
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (cubesc_case_1 == nullptr) return false;
|
||||
Instruction* cubesc_case_2 = ir_builder.AddSelect(
|
||||
float_type_id, is_x_neg->result_id(), z->result_id(), nz->result_id());
|
||||
if (cubesc_case_2 == nullptr) return false;
|
||||
Instruction* sel =
|
||||
// TODO(1841): Handle id overflow.
|
||||
ir_builder.AddSelect(float_type_id, is_y_max->result_id(), x->result_id(),
|
||||
cubesc_case_2->result_id());
|
||||
if (sel == nullptr) return false;
|
||||
Instruction* cubesc =
|
||||
// TODO(1841): Handle id overflow.
|
||||
ir_builder.AddSelect(float_type_id, is_z_max->result_id(),
|
||||
cubesc_case_1->result_id(), sel->result_id());
|
||||
if (cubesc == nullptr) return false;
|
||||
|
||||
// Select the correct value for cubetc.
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* cubetc_case_1 = ir_builder.AddSelect(
|
||||
float_type_id, is_y_neg->result_id(), nz->result_id(), z->result_id());
|
||||
if (cubetc_case_1 == nullptr) return false;
|
||||
Instruction* cubetc =
|
||||
// TODO(1841): Handle id overflow.
|
||||
ir_builder.AddSelect(float_type_id, is_y_max->result_id(),
|
||||
cubetc_case_1->result_id(), ny->result_id());
|
||||
if (cubetc == nullptr) return false;
|
||||
|
||||
// Do the division
|
||||
Instruction* cube = ir_builder.AddCompositeConstruct(
|
||||
v2_float_type_id, {cubesc->result_id(), cubetc->result_id()});
|
||||
if (cube == nullptr) return false;
|
||||
Instruction* denom = ir_builder.AddCompositeConstruct(
|
||||
v2_float_type_id, {cubema->result_id(), cubema->result_id()});
|
||||
if (denom == nullptr) return false;
|
||||
Instruction* div = ir_builder.AddBinaryOp(
|
||||
v2_float_type_id, spv::Op::OpFDiv, cube->result_id(), denom->result_id());
|
||||
if (div == nullptr) return false;
|
||||
@@ -756,7 +827,9 @@ bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
|
||||
analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
|
||||
|
||||
uint32_t float_type_id = type_mgr->GetFloatTypeId();
|
||||
if (float_type_id == 0) return false;
|
||||
uint32_t bool_id = type_mgr->GetBoolTypeId();
|
||||
if (bool_id == 0) return false;
|
||||
|
||||
InstructionBuilder ir_builder(
|
||||
ctx, inst,
|
||||
@@ -773,27 +846,37 @@ bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
|
||||
|
||||
// Get the constants that will be used.
|
||||
uint32_t f0_const_id = const_mgr->GetFloatConstId(0.0);
|
||||
if (f0_const_id == 0) return false;
|
||||
uint32_t f1_const_id = const_mgr->GetFloatConstId(1.0);
|
||||
if (f1_const_id == 0) return false;
|
||||
uint32_t f2_const_id = const_mgr->GetFloatConstId(2.0);
|
||||
if (f2_const_id == 0) return false;
|
||||
uint32_t f3_const_id = const_mgr->GetFloatConstId(3.0);
|
||||
if (f3_const_id == 0) return false;
|
||||
uint32_t f4_const_id = const_mgr->GetFloatConstId(4.0);
|
||||
if (f4_const_id == 0) return false;
|
||||
uint32_t f5_const_id = const_mgr->GetFloatConstId(5.0);
|
||||
if (f5_const_id == 0) return false;
|
||||
|
||||
// Extract the input values.
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0});
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (x == nullptr) return false;
|
||||
Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1});
|
||||
if (y == nullptr) return false;
|
||||
// TODO(1-841): Handle id overflow.
|
||||
Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2});
|
||||
if (z == nullptr) return false;
|
||||
|
||||
// Get the absolute values of the inputs.
|
||||
Instruction* ax = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()});
|
||||
if (ax == nullptr) return false;
|
||||
Instruction* ay = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()});
|
||||
if (ay == nullptr) return false;
|
||||
Instruction* az = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
|
||||
if (az == nullptr) return false;
|
||||
|
||||
// Find which values are negative. Used in later computations.
|
||||
Instruction* is_z_neg = ir_builder.AddBinaryOp(
|
||||
@@ -810,6 +893,7 @@ bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
|
||||
Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
|
||||
float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
|
||||
{ax->result_id(), ay->result_id()});
|
||||
if (amax_x_y == nullptr) return false;
|
||||
Instruction* is_z_max =
|
||||
ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
|
||||
az->result_id(), amax_x_y->result_id());
|
||||
@@ -820,21 +904,21 @@ bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
|
||||
if (y_gr_x == nullptr) return false;
|
||||
|
||||
// Get the value for each case.
|
||||
// TODO(1841): Handle id overflow.
|
||||
Instruction* case_z = ir_builder.AddSelect(
|
||||
float_type_id, is_z_neg->result_id(), f5_const_id, f4_const_id);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (case_z == nullptr) return false;
|
||||
Instruction* case_y = ir_builder.AddSelect(
|
||||
float_type_id, is_y_neg->result_id(), f3_const_id, f2_const_id);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (case_y == nullptr) return false;
|
||||
Instruction* case_x = ir_builder.AddSelect(
|
||||
float_type_id, is_x_neg->result_id(), f1_const_id, f0_const_id);
|
||||
if (case_x == nullptr) return false;
|
||||
|
||||
// Select the correct case.
|
||||
Instruction* sel =
|
||||
// TODO(1841): Handle id overflow.
|
||||
ir_builder.AddSelect(float_type_id, y_gr_x->result_id(),
|
||||
case_y->result_id(), case_x->result_id());
|
||||
if (sel == nullptr) return false;
|
||||
|
||||
// Get the final result by adding 0.5 to |div|.
|
||||
inst->SetOpcode(spv::Op::OpSelect);
|
||||
@@ -974,11 +1058,18 @@ Pass::Status AmdExtensionToKhrPass::Process() {
|
||||
std::unique_ptr<AmdExtFoldingRules>(new AmdExtFoldingRules(context())),
|
||||
MakeUnique<AmdExtConstFoldingRules>(context()));
|
||||
for (Function& func : *get_module()) {
|
||||
func.ForEachInst([&changed, &folder](Instruction* inst) {
|
||||
if (folder.FoldInstruction(inst)) {
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
bool failed =
|
||||
!func.WhileEachInst([&changed, &folder, this](Instruction* inst) {
|
||||
if (folder.FoldInstruction(inst)) {
|
||||
changed = true;
|
||||
return true;
|
||||
} else if (context()->id_overflow()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (failed) return Status::Failure;
|
||||
}
|
||||
|
||||
// Now that instruction that require the extensions have been removed, we can
|
||||
|
||||
@@ -462,7 +462,9 @@ const Constant* ConstantManager::GetNumericVectorConstantWithWords(
|
||||
|
||||
uint32_t ConstantManager::GetFloatConstId(float val) {
|
||||
const Constant* c = GetFloatConst(val);
|
||||
return GetDefiningInstruction(c)->result_id();
|
||||
Instruction* inst = GetDefiningInstruction(c);
|
||||
if (inst == nullptr) return 0;
|
||||
return inst->result_id();
|
||||
}
|
||||
|
||||
const Constant* ConstantManager::GetFloatConst(float val) {
|
||||
@@ -474,7 +476,9 @@ const Constant* ConstantManager::GetFloatConst(float val) {
|
||||
|
||||
uint32_t ConstantManager::GetDoubleConstId(double val) {
|
||||
const Constant* c = GetDoubleConst(val);
|
||||
return GetDefiningInstruction(c)->result_id();
|
||||
Instruction* inst = GetDefiningInstruction(c);
|
||||
if (inst == nullptr) return 0;
|
||||
return inst->result_id();
|
||||
}
|
||||
|
||||
const Constant* ConstantManager::GetDoubleConst(double val) {
|
||||
|
||||
232
3rdparty/spirv-tools/source/opt/folding_rules.cpp
vendored
232
3rdparty/spirv-tools/source/opt/folding_rules.cpp
vendored
@@ -194,7 +194,7 @@ std::vector<uint32_t> GetWordsFromNumericScalarOrVectorConstant(
|
||||
uint32_t compacted_word = 0;
|
||||
for (int32_t i = static_cast<int32_t>(words.size()) - 1; i >= 0; --i) {
|
||||
compacted_word <<= 8;
|
||||
compacted_word |= words[i];
|
||||
compacted_word |= (words[i] & 0xFF);
|
||||
}
|
||||
return {compacted_word};
|
||||
} else if (ElementWidth(c->type()) == 16) {
|
||||
@@ -205,7 +205,7 @@ std::vector<uint32_t> GetWordsFromNumericScalarOrVectorConstant(
|
||||
for (uint32_t i = 0; i < words.size(); i += 2) {
|
||||
uint32_t word1 = words[i];
|
||||
uint32_t word2 = (i + 1 < words.size()) ? words[i + 1] : 0;
|
||||
uint32_t compacted_word = (word2 << 16) | word1;
|
||||
uint32_t compacted_word = (word2 << 16) | (word1 & 0xFFFF);
|
||||
compacted_words.push_back(compacted_word);
|
||||
}
|
||||
return compacted_words;
|
||||
@@ -2819,6 +2819,230 @@ FoldingRule RedundantSUMod() {
|
||||
};
|
||||
}
|
||||
|
||||
// Utility function for applying |callback| to |input1| and |input2|.
|
||||
// If they are vectors it applies element wise.
|
||||
// The constants |input1| and |input2| must be integers or a vector of integers.
|
||||
template <typename Callback>
|
||||
void ForEachIntegerConstantPair(analysis::ConstantManager* const_mgr,
|
||||
const analysis::Constant* input1,
|
||||
const analysis::Constant* input2,
|
||||
Callback&& callback) {
|
||||
assert(input1 && input2);
|
||||
|
||||
auto Dispatch = [&callback](const analysis::Constant* lhs,
|
||||
const analysis::Constant* rhs) {
|
||||
assert(lhs->type()->AsInteger());
|
||||
const analysis::Integer* type = lhs->type()->AsInteger();
|
||||
uint32_t width = type->AsInteger()->width();
|
||||
assert(width == 32 || width == 64);
|
||||
if (width == 32) {
|
||||
callback(lhs->GetU32(), rhs->GetU32());
|
||||
} else {
|
||||
callback(lhs->GetU64(), rhs->GetU64());
|
||||
}
|
||||
};
|
||||
|
||||
const analysis::Type* type = input1->type();
|
||||
if (const analysis::Vector* vector_type = type->AsVector()) {
|
||||
const analysis::Type* ele_type = vector_type->element_type();
|
||||
assert(ele_type->AsInteger());
|
||||
for (uint32_t i = 0; i != vector_type->element_count(); ++i) {
|
||||
const analysis::Constant* input1_comp = nullptr;
|
||||
if (const analysis::VectorConstant* input1_vector =
|
||||
input1->AsVectorConstant()) {
|
||||
input1_comp = input1_vector->GetComponents()[i];
|
||||
} else {
|
||||
assert(input1->AsNullConstant());
|
||||
input1_comp = const_mgr->GetConstant(ele_type, {});
|
||||
}
|
||||
|
||||
const analysis::Constant* input2_comp = nullptr;
|
||||
if (const analysis::VectorConstant* input2_vector =
|
||||
input2->AsVectorConstant()) {
|
||||
input2_comp = input2_vector->GetComponents()[i];
|
||||
} else {
|
||||
assert(input2->AsNullConstant());
|
||||
input2_comp = const_mgr->GetConstant(ele_type, {});
|
||||
}
|
||||
|
||||
assert(ele_type->AsInteger());
|
||||
Dispatch(input1_comp, input2_comp);
|
||||
}
|
||||
|
||||
} else {
|
||||
assert(type->AsInteger());
|
||||
Dispatch(input1, input2);
|
||||
}
|
||||
}
|
||||
|
||||
// Folds redundant xor and or ops that are part of an and.
|
||||
// Cases handled:
|
||||
// 0b1110 & (a | 0b0001) = a & 0b1110
|
||||
// 0b1110 & (a ^ 0b0001) = a & 0b1110
|
||||
// 0b0110 & (a | 0b1110) = 0b0110
|
||||
FoldingRule RedundantAndOrXor() {
|
||||
return [](IRContext* context, Instruction* inst,
|
||||
const std::vector<const analysis::Constant*>& constants) {
|
||||
assert(inst->opcode() == spv::Op::OpBitwiseAnd && "Wrong opcode.");
|
||||
const analysis::Type* type =
|
||||
context->get_type_mgr()->GetType(inst->type_id());
|
||||
uint32_t width = ElementWidth(type);
|
||||
if ((width != 32) && (width != 64)) return false;
|
||||
|
||||
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
|
||||
const analysis::Constant* const_input1 = ConstInput(constants);
|
||||
if (!const_input1) return false;
|
||||
Instruction* other_inst = NonConstInput(context, constants[0], inst);
|
||||
|
||||
if (other_inst->opcode() == spv::Op::OpBitwiseOr ||
|
||||
other_inst->opcode() == spv::Op::OpBitwiseXor) {
|
||||
std::vector<const analysis::Constant*> other_constants =
|
||||
const_mgr->GetOperandConstants(other_inst);
|
||||
const analysis::Constant* const_input2 = ConstInput(other_constants);
|
||||
if (!const_input2) return false;
|
||||
|
||||
bool can_convert_to_const = other_inst->opcode() == spv::Op::OpBitwiseOr;
|
||||
bool can_remove_inner = true;
|
||||
|
||||
ForEachIntegerConstantPair(
|
||||
const_mgr, const_input1, const_input2,
|
||||
[&can_remove_inner, &can_convert_to_const](auto lhs, auto rhs) {
|
||||
// Only convert to const if 'and' is a subset of 'or'
|
||||
can_convert_to_const = can_convert_to_const && ((lhs & rhs) == lhs);
|
||||
// Only remove 'xor'/'or' if no bits intersect with 'and'
|
||||
can_remove_inner = can_remove_inner && ((lhs & rhs) == 0);
|
||||
});
|
||||
|
||||
if (can_convert_to_const) {
|
||||
Instruction* const_inst =
|
||||
const_mgr->GetDefiningInstruction(const_input1);
|
||||
inst->SetOpcode(spv::Op::OpCopyObject);
|
||||
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {const_inst->result_id()}}});
|
||||
return true;
|
||||
} else if (can_remove_inner) {
|
||||
Instruction* non_const_input =
|
||||
NonConstInput(context, other_constants[0], other_inst);
|
||||
Instruction* const_inst =
|
||||
const_mgr->GetDefiningInstruction(const_input1);
|
||||
inst->SetInOperands(
|
||||
{{SPV_OPERAND_TYPE_ID, {non_const_input->result_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {const_inst->result_id()}}});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
// Folds redundant add and sub ops that are part of an and.
|
||||
// Cases handled:
|
||||
// 1 & (b + 2) = b & 1
|
||||
// 1 & (b - 2) = b & 1
|
||||
FoldingRule RedundantAndAddSub() {
|
||||
return [](IRContext* context, Instruction* inst,
|
||||
const std::vector<const analysis::Constant*>& constants) {
|
||||
assert(inst->opcode() == spv::Op::OpBitwiseAnd && "Wrong opcode.");
|
||||
const analysis::Type* type =
|
||||
context->get_type_mgr()->GetType(inst->type_id());
|
||||
uint32_t width = ElementWidth(type);
|
||||
if ((width != 32) && (width != 64)) return false;
|
||||
|
||||
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
|
||||
const analysis::Constant* const_input1 = ConstInput(constants);
|
||||
if (!const_input1) return false;
|
||||
Instruction* other_inst = NonConstInput(context, constants[0], inst);
|
||||
|
||||
if (other_inst->opcode() != spv::Op::OpIAdd &&
|
||||
other_inst->opcode() != spv::Op::OpISub) {
|
||||
return false;
|
||||
}
|
||||
std::vector<const analysis::Constant*> other_constants =
|
||||
const_mgr->GetOperandConstants(other_inst);
|
||||
const analysis::Constant* const_input2 = ConstInput(other_constants);
|
||||
if (!const_input2) return false;
|
||||
|
||||
// Only valid for subtraction if const is on the right
|
||||
if ((other_inst->opcode() == spv::Op::OpISub) && other_constants[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool can_remove_inner = true;
|
||||
ForEachIntegerConstantPair(const_mgr, const_input1, const_input2,
|
||||
[&can_remove_inner](auto and_op, auto add_op) {
|
||||
if (can_remove_inner) {
|
||||
// Only valid if no bits from the +/- could
|
||||
// affect bits from the & operation.
|
||||
can_remove_inner =
|
||||
utils::LSB(add_op) > and_op;
|
||||
}
|
||||
});
|
||||
|
||||
if (can_remove_inner) {
|
||||
Instruction* non_const_input =
|
||||
NonConstInput(context, other_constants[0], other_inst);
|
||||
Instruction* const_inst = const_mgr->GetDefiningInstruction(const_input1);
|
||||
inst->SetInOperands(
|
||||
{{SPV_OPERAND_TYPE_ID, {non_const_input->result_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {const_inst->result_id()}}});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
// Folds redundant shift ops that are part of an and.
|
||||
// Cases handled:
|
||||
// 1 & (b << 1) = 0
|
||||
// 0x80000000 & (b >> 1) = 0
|
||||
FoldingRule RedundantAndShift() {
|
||||
return [](IRContext* context, Instruction* inst,
|
||||
const std::vector<const analysis::Constant*>& constants) {
|
||||
assert(inst->opcode() == spv::Op::OpBitwiseAnd && "Wrong opcode.");
|
||||
const analysis::Type* type =
|
||||
context->get_type_mgr()->GetType(inst->type_id());
|
||||
uint32_t width = ElementWidth(type);
|
||||
if ((width != 32) && (width != 64)) return false;
|
||||
|
||||
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
|
||||
const analysis::Constant* const_input1 = ConstInput(constants);
|
||||
if (!const_input1) return false;
|
||||
Instruction* other_inst = NonConstInput(context, constants[0], inst);
|
||||
|
||||
spv::Op other_op = other_inst->opcode();
|
||||
if (other_op == spv::Op::OpShiftLeftLogical ||
|
||||
other_op == spv::Op::OpShiftRightLogical) {
|
||||
std::vector<const analysis::Constant*> other_constants =
|
||||
const_mgr->GetOperandConstants(other_inst);
|
||||
|
||||
// Only valid if const is on the right
|
||||
if (other_constants[0]) {
|
||||
return false;
|
||||
}
|
||||
const analysis::Constant* const_input2 = other_constants[1];
|
||||
if (!const_input2) return false;
|
||||
|
||||
bool can_convert_to_zero = true;
|
||||
ForEachIntegerConstantPair(
|
||||
const_mgr, const_input1, const_input2,
|
||||
[&can_convert_to_zero, other_op](auto lhs, auto rhs) {
|
||||
if (other_op == spv::Op::OpShiftRightLogical) {
|
||||
can_convert_to_zero = can_convert_to_zero && (lhs << rhs) == 0;
|
||||
} else {
|
||||
can_convert_to_zero = can_convert_to_zero && (lhs >> rhs) == 0;
|
||||
}
|
||||
});
|
||||
|
||||
if (can_convert_to_zero) {
|
||||
auto zero_id = context->get_constant_mgr()->GetNullConstId(type);
|
||||
inst->SetOpcode(spv::Op::OpCopyObject);
|
||||
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {zero_id}}});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
// This rule look for a dot with a constant vector containing a single 1 and
|
||||
// the rest 0s. This is the same as doing an extract.
|
||||
FoldingRule DotProductDoingExtract() {
|
||||
@@ -3231,6 +3455,10 @@ void FoldingRules::AddFoldingRules() {
|
||||
rules_[spv::Op::OpISub].push_back(MergeSubAddArithmetic());
|
||||
rules_[spv::Op::OpISub].push_back(MergeSubSubArithmetic());
|
||||
|
||||
rules_[spv::Op::OpBitwiseAnd].push_back(RedundantAndOrXor());
|
||||
rules_[spv::Op::OpBitwiseAnd].push_back(RedundantAndAddSub());
|
||||
rules_[spv::Op::OpBitwiseAnd].push_back(RedundantAndShift());
|
||||
|
||||
rules_[spv::Op::OpPhi].push_back(RedundantPhi());
|
||||
|
||||
rules_[spv::Op::OpSNegate].push_back(MergeNegateArithmetic());
|
||||
|
||||
@@ -557,6 +557,7 @@ void IRContext::AddCombinatorsForCapability(uint32_t capability) {
|
||||
(uint32_t)spv::Op::OpTypeAccelerationStructureKHR,
|
||||
(uint32_t)spv::Op::OpTypeRayQueryKHR,
|
||||
(uint32_t)spv::Op::OpTypeHitObjectNV,
|
||||
(uint32_t)spv::Op::OpTypeHitObjectEXT,
|
||||
(uint32_t)spv::Op::OpTypeArray,
|
||||
(uint32_t)spv::Op::OpTypeRuntimeArray,
|
||||
(uint32_t)spv::Op::OpTypeNodePayloadArrayAMDX,
|
||||
@@ -927,11 +928,13 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (reg_type == nullptr) return 0; // Error
|
||||
|
||||
uint32_t type_id = type_mgr->GetTypeInstruction(reg_type);
|
||||
uint32_t varTyPtrId =
|
||||
type_mgr->FindPointerToType(type_id, spv::StorageClass::Input);
|
||||
// TODO(1841): Handle id overflow.
|
||||
var_id = TakeNextId();
|
||||
if (var_id == 0) return 0; // Error
|
||||
std::unique_ptr<Instruction> newVarOp(
|
||||
new Instruction(this, spv::Op::OpVariable, varTyPtrId, var_id,
|
||||
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
|
||||
|
||||
@@ -467,6 +467,7 @@ void LocalAccessChainConvertPass::InitExtensions() {
|
||||
"SPV_NV_shader_invocation_reorder",
|
||||
"SPV_NV_cluster_acceleration_structure",
|
||||
"SPV_NV_linear_swept_spheres",
|
||||
"SPV_KHR_maximal_reconvergence",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -304,6 +304,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
|
||||
"SPV_NV_shader_invocation_reorder",
|
||||
"SPV_NV_cluster_acceleration_structure",
|
||||
"SPV_NV_linear_swept_spheres",
|
||||
"SPV_KHR_maximal_reconvergence",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() {
|
||||
"SPV_NV_shader_invocation_reorder",
|
||||
"SPV_NV_cluster_acceleration_structure",
|
||||
"SPV_NV_linear_swept_spheres",
|
||||
"SPV_KHR_maximal_reconvergence",
|
||||
});
|
||||
}
|
||||
bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
|
||||
|
||||
@@ -930,13 +930,13 @@ LoopDescriptor::Status LoopDescriptor::CreatePreHeaderBlocksIfMissing() {
|
||||
for (auto& loop : *this) {
|
||||
if (!loop.GetPreHeaderBlock()) {
|
||||
if (!loop.GetOrCreatePreHeaderBlock()) {
|
||||
return Status::kFailure;
|
||||
return Status::Failure;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
return modified ? Status::kSuccessWithChange : Status::kSuccessWithoutChange;
|
||||
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
// Add and remove loops which have been marked for addition and removal to
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "source/opt/dominator_analysis.h"
|
||||
#include "source/opt/module.h"
|
||||
#include "source/opt/tree_iterator.h"
|
||||
#include "source/util/status.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
@@ -426,7 +427,7 @@ class LoopDescriptor {
|
||||
using const_pre_iterator = TreeDFIterator<const Loop>;
|
||||
|
||||
// The status of processing a module.
|
||||
enum class Status { kSuccessWithChange, kSuccessWithoutChange, kFailure };
|
||||
using Status = utils::Status;
|
||||
|
||||
// Creates a loop object for all loops found in |f|.
|
||||
LoopDescriptor(IRContext* context, const Function* f);
|
||||
|
||||
@@ -41,8 +41,8 @@ Pass::Status LoopFusionPass::ProcessFunction(Function* function) {
|
||||
// sure to return Status::SuccessWithChange in that case.
|
||||
bool modified = false;
|
||||
auto status = ld.CreatePreHeaderBlocksIfMissing();
|
||||
if (status == LoopDescriptor::Status::kFailure) return Status::Failure;
|
||||
modified = status == LoopDescriptor::Status::kSuccessWithChange;
|
||||
if (status == LoopDescriptor::Status::Failure) return Status::Failure;
|
||||
modified = status == LoopDescriptor::Status::SuccessWithChange;
|
||||
|
||||
// TODO(tremmelg): Could the only loop that |loop| could possibly be fused be
|
||||
// picked out so don't have to check every loop
|
||||
|
||||
@@ -938,6 +938,11 @@ bool LoopUnrollerUtilsImpl::AssignNewResultIds(BasicBlock* basic_block) {
|
||||
inst.SetResultId(new_id);
|
||||
def_use_mgr->AnalyzeInstDef(&inst);
|
||||
|
||||
// All decorations that can apply to an instruction in a function body
|
||||
// modify the behaviour of the instruction, and should be on the
|
||||
// new instruction to keep the same results.
|
||||
context_->get_decoration_mgr()->CloneDecorations(old_id, new_id);
|
||||
|
||||
// Save the mapping of old_id -> new_id.
|
||||
state_.new_inst[old_id] = inst.result_id();
|
||||
// Check if this instruction is the induction variable.
|
||||
|
||||
7
3rdparty/spirv-tools/source/opt/pass.h
vendored
7
3rdparty/spirv-tools/source/opt/pass.h
vendored
@@ -25,6 +25,7 @@
|
||||
#include "source/opt/def_use_manager.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/opt/module.h"
|
||||
#include "source/util/status.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
#include "types.h"
|
||||
|
||||
@@ -46,11 +47,7 @@ class Pass {
|
||||
//
|
||||
// The numbers for the cases are assigned to make sure that Failure & anything
|
||||
// is Failure, SuccessWithChange & any success is SuccessWithChange.
|
||||
enum class Status {
|
||||
Failure = 0x00,
|
||||
SuccessWithChange = 0x10,
|
||||
SuccessWithoutChange = 0x11,
|
||||
};
|
||||
using Status = utils::Status;
|
||||
|
||||
using ProcessFunction = std::function<bool(Function*)>;
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ Instruction* SplitCombinedImageSamplerPass::GetSamplerType() {
|
||||
analysis::Sampler s;
|
||||
uint32_t sampler_type_id = type_mgr_->GetTypeInstruction(&s);
|
||||
sampler_type_ = def_use_mgr_->GetDef(sampler_type_id);
|
||||
if (sampler_type_ == nullptr) return nullptr;
|
||||
assert(first_sampled_image_type_);
|
||||
sampler_type_->InsertBefore(first_sampled_image_type_);
|
||||
RegisterNewGlobal(sampler_type_->result_id());
|
||||
@@ -169,6 +170,7 @@ std::pair<Instruction*, Instruction*> SplitCombinedImageSamplerPass::SplitType(
|
||||
auto* image_type =
|
||||
def_use_mgr_->GetDef(combined_kind_type.GetSingleWordInOperand(0));
|
||||
auto* sampler_type = GetSamplerType();
|
||||
if (!sampler_type) return {nullptr, nullptr};
|
||||
type_remap_[combined_kind_type.result_id()] = {&combined_kind_type,
|
||||
image_type, sampler_type};
|
||||
return {image_type, sampler_type};
|
||||
@@ -187,7 +189,9 @@ std::pair<Instruction*, Instruction*> SplitCombinedImageSamplerPass::SplitType(
|
||||
// this defensively.
|
||||
if (image_pointee && sampler_pointee) {
|
||||
auto* ptr_image = MakeUniformConstantPointer(image_pointee);
|
||||
if (!ptr_image) return {nullptr, nullptr};
|
||||
auto* ptr_sampler = MakeUniformConstantPointer(sampler_pointee);
|
||||
if (!ptr_sampler) return {nullptr, nullptr};
|
||||
type_remap_[combined_kind_type.result_id()] = {
|
||||
&combined_kind_type, ptr_image, ptr_sampler};
|
||||
return {ptr_image, ptr_sampler};
|
||||
@@ -207,6 +211,7 @@ std::pair<Instruction*, Instruction*> SplitCombinedImageSamplerPass::SplitType(
|
||||
analysis::Array array_image_ty(image_ty, array_ty->length_info());
|
||||
const uint32_t array_image_ty_id =
|
||||
type_mgr_->GetTypeInstruction(&array_image_ty);
|
||||
if (array_image_ty_id == 0) return {nullptr, nullptr};
|
||||
auto* array_image_ty_inst = def_use_mgr_->GetDef(array_image_ty_id);
|
||||
if (!IsKnownGlobal(array_image_ty_id)) {
|
||||
array_image_ty_inst->InsertBefore(&combined_kind_type);
|
||||
@@ -214,11 +219,14 @@ std::pair<Instruction*, Instruction*> SplitCombinedImageSamplerPass::SplitType(
|
||||
// GetTypeInstruction also updated the def-use manager.
|
||||
}
|
||||
|
||||
auto* sampler_ty_inst = GetSamplerType();
|
||||
if (!sampler_ty_inst) return {nullptr, nullptr};
|
||||
analysis::Array sampler_array_ty(
|
||||
type_mgr_->GetType(GetSamplerType()->result_id()),
|
||||
type_mgr_->GetType(sampler_ty_inst->result_id()),
|
||||
array_ty->length_info());
|
||||
const uint32_t array_sampler_ty_id =
|
||||
type_mgr_->GetTypeInstruction(&sampler_array_ty);
|
||||
if (array_sampler_ty_id == 0) return {nullptr, nullptr};
|
||||
auto* array_sampler_ty_inst = def_use_mgr_->GetDef(array_sampler_ty_id);
|
||||
if (!IsKnownGlobal(array_sampler_ty_id)) {
|
||||
array_sampler_ty_inst->InsertBefore(&combined_kind_type);
|
||||
@@ -240,6 +248,7 @@ std::pair<Instruction*, Instruction*> SplitCombinedImageSamplerPass::SplitType(
|
||||
analysis::RuntimeArray array_image_ty(image_ty);
|
||||
const uint32_t array_image_ty_id =
|
||||
type_mgr_->GetTypeInstruction(&array_image_ty);
|
||||
if (array_image_ty_id == 0) return {nullptr, nullptr};
|
||||
auto* array_image_ty_inst = def_use_mgr_->GetDef(array_image_ty_id);
|
||||
if (!IsKnownGlobal(array_image_ty_id)) {
|
||||
array_image_ty_inst->InsertBefore(&combined_kind_type);
|
||||
@@ -247,10 +256,13 @@ std::pair<Instruction*, Instruction*> SplitCombinedImageSamplerPass::SplitType(
|
||||
// GetTypeInstruction also updated the def-use manager.
|
||||
}
|
||||
|
||||
auto* sampler_ty_inst = GetSamplerType();
|
||||
if (!sampler_ty_inst) return {nullptr, nullptr};
|
||||
analysis::RuntimeArray sampler_array_ty(
|
||||
type_mgr_->GetType(GetSamplerType()->result_id()));
|
||||
type_mgr_->GetType(sampler_ty_inst->result_id()));
|
||||
const uint32_t array_sampler_ty_id =
|
||||
type_mgr_->GetTypeInstruction(&sampler_array_ty);
|
||||
if (array_sampler_ty_id == 0) return {nullptr, nullptr};
|
||||
auto* array_sampler_ty_inst = def_use_mgr_->GetDef(array_sampler_ty_id);
|
||||
if (!IsKnownGlobal(array_sampler_ty_id)) {
|
||||
array_sampler_ty_inst->InsertBefore(&combined_kind_type);
|
||||
@@ -273,14 +285,14 @@ spv_result_t SplitCombinedImageSamplerPass::RemapVar(
|
||||
// Create an image variable, and a sampler variable.
|
||||
auto* combined_var_type = def_use_mgr_->GetDef(combined_var->type_id());
|
||||
auto [ptr_image_ty, ptr_sampler_ty] = SplitType(*combined_var_type);
|
||||
assert(ptr_image_ty);
|
||||
assert(ptr_sampler_ty);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (!ptr_image_ty || !ptr_sampler_ty) return SPV_ERROR_INTERNAL;
|
||||
Instruction* sampler_var = builder.AddVariable(
|
||||
ptr_sampler_ty->result_id(), SpvStorageClassUniformConstant);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (sampler_var == nullptr) return SPV_ERROR_INTERNAL;
|
||||
Instruction* image_var = builder.AddVariable(ptr_image_ty->result_id(),
|
||||
SpvStorageClassUniformConstant);
|
||||
if (image_var == nullptr) return SPV_ERROR_INTERNAL;
|
||||
|
||||
modified_ = true;
|
||||
return RemapUses(combined_var, image_var, sampler_var);
|
||||
}
|
||||
@@ -356,12 +368,12 @@ spv_result_t SplitCombinedImageSamplerPass::RemapUses(
|
||||
|
||||
// Create loads for the image part and sampler part.
|
||||
builder.SetInsertPoint(load);
|
||||
// TODO(1841): Handle id overflow.
|
||||
auto* image = builder.AddLoad(PointeeTypeId(use.image_part),
|
||||
use.image_part->result_id());
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (!image) return SPV_ERROR_INTERNAL;
|
||||
auto* sampler = builder.AddLoad(PointeeTypeId(use.sampler_part),
|
||||
use.sampler_part->result_id());
|
||||
if (!sampler) return SPV_ERROR_INTERNAL;
|
||||
|
||||
// Move decorations, such as RelaxedPrecision.
|
||||
auto* deco_mgr = context()->get_decoration_mgr();
|
||||
@@ -372,6 +384,7 @@ spv_result_t SplitCombinedImageSamplerPass::RemapUses(
|
||||
// Create a sampled image from the loads of the two parts.
|
||||
auto* sampled_image = builder.AddSampledImage(
|
||||
load->type_id(), image->result_id(), sampler->result_id());
|
||||
if (!sampled_image) return SPV_ERROR_INTERNAL;
|
||||
// Replace the original sampled image value with the new one.
|
||||
std::unordered_set<Instruction*> users;
|
||||
def_use_mgr_->ForEachUse(
|
||||
@@ -463,14 +476,18 @@ spv_result_t SplitCombinedImageSamplerPass::RemapUses(
|
||||
|
||||
auto [result_image_part_ty, result_sampler_part_ty] =
|
||||
SplitType(*def_use_mgr_->GetDef(original_access_chain->type_id()));
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (!result_image_part_ty || !result_sampler_part_ty)
|
||||
return Fail() << "failed to split type for access chain";
|
||||
auto* result_image_part = builder.AddOpcodeAccessChain(
|
||||
use.user->opcode(), result_image_part_ty->result_id(),
|
||||
use.image_part->result_id(), indices);
|
||||
// TODO(1841): Handle id overflow.
|
||||
if (!result_image_part)
|
||||
return Fail() << "failed to create access chain for image part";
|
||||
auto* result_sampler_part = builder.AddOpcodeAccessChain(
|
||||
use.user->opcode(), result_sampler_part_ty->result_id(),
|
||||
use.sampler_part->result_id(), indices);
|
||||
if (!result_sampler_part)
|
||||
return Fail() << "failed to create access chain for sampler part";
|
||||
|
||||
// Remap uses of the original access chain.
|
||||
add_remap(original_access_chain, result_image_part,
|
||||
@@ -521,8 +538,7 @@ spv_result_t SplitCombinedImageSamplerPass::RemapFunctions() {
|
||||
if (combined_types_.find(param_ty_id) != combined_types_.end()) {
|
||||
auto* param_type = def_use_mgr_->GetDef(param_ty_id);
|
||||
auto [image_type, sampler_type] = SplitType(*param_type);
|
||||
assert(image_type);
|
||||
assert(sampler_type);
|
||||
if (!image_type || !sampler_type) return SPV_ERROR_INTERNAL;
|
||||
// The image and sampler types must already exist, so there is no
|
||||
// need to move them to the right spot.
|
||||
new_params.push_back(type_mgr_->GetType(image_type->result_id()));
|
||||
@@ -579,6 +595,11 @@ spv_result_t SplitCombinedImageSamplerPass::RemapFunctions() {
|
||||
auto* combined_inst = param.release();
|
||||
auto* combined_type = def_use_mgr_->GetDef(combined_inst->type_id());
|
||||
auto [image_type, sampler_type] = SplitType(*combined_type);
|
||||
if (!image_type || !sampler_type) {
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t image_param_id = context()->TakeNextId();
|
||||
if (image_param_id == 0) {
|
||||
error = true;
|
||||
@@ -621,6 +642,7 @@ Instruction* SplitCombinedImageSamplerPass::MakeUniformConstantPointer(
|
||||
Instruction* pointee) {
|
||||
uint32_t ptr_id = type_mgr_->FindPointerToType(
|
||||
pointee->result_id(), spv::StorageClass::UniformConstant);
|
||||
if (ptr_id == 0) return nullptr;
|
||||
auto* ptr = def_use_mgr_->GetDef(ptr_id);
|
||||
if (!IsKnownGlobal(ptr_id)) {
|
||||
// The pointer type was created at the end. Put it right after the
|
||||
|
||||
@@ -237,6 +237,7 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) {
|
||||
DefineParameterlessCase(AccelerationStructureNV);
|
||||
DefineParameterlessCase(RayQueryKHR);
|
||||
DefineParameterlessCase(HitObjectNV);
|
||||
DefineParameterlessCase(HitObjectEXT);
|
||||
#undef DefineParameterlessCase
|
||||
case Type::kInteger:
|
||||
typeInst = MakeUnique<Instruction>(
|
||||
@@ -654,6 +655,7 @@ Type* TypeManager::RebuildType(uint32_t type_id, const Type& type) {
|
||||
DefineNoSubtypeCase(AccelerationStructureNV);
|
||||
DefineNoSubtypeCase(RayQueryKHR);
|
||||
DefineNoSubtypeCase(HitObjectNV);
|
||||
DefineNoSubtypeCase(HitObjectEXT);
|
||||
#undef DefineNoSubtypeCase
|
||||
case Type::kVector: {
|
||||
const Vector* vec_ty = type.AsVector();
|
||||
@@ -1082,6 +1084,9 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) {
|
||||
case spv::Op::OpTypeHitObjectNV:
|
||||
type = new HitObjectNV();
|
||||
break;
|
||||
case spv::Op::OpTypeHitObjectEXT:
|
||||
type = new HitObjectEXT();
|
||||
break;
|
||||
case spv::Op::OpTypeTensorLayoutNV:
|
||||
type = new TensorLayoutNV(inst.GetSingleWordInOperand(0),
|
||||
inst.GetSingleWordInOperand(1));
|
||||
|
||||
@@ -203,7 +203,11 @@ class TypeManager {
|
||||
return GetRegisteredType(&bool_type);
|
||||
}
|
||||
|
||||
uint32_t GetBoolTypeId() { return GetTypeInstruction(GetBoolType()); }
|
||||
uint32_t GetBoolTypeId() {
|
||||
Type* bool_type = GetBoolType();
|
||||
if (bool_type == nullptr) return 0;
|
||||
return GetTypeInstruction(bool_type);
|
||||
}
|
||||
|
||||
Type* GetVoidType() {
|
||||
Void void_type;
|
||||
|
||||
3
3rdparty/spirv-tools/source/opt/types.cpp
vendored
3
3rdparty/spirv-tools/source/opt/types.cpp
vendored
@@ -135,6 +135,7 @@ std::unique_ptr<Type> Type::Clone() const {
|
||||
DeclareKindCase(CooperativeVectorNV);
|
||||
DeclareKindCase(RayQueryKHR);
|
||||
DeclareKindCase(HitObjectNV);
|
||||
DeclareKindCase(HitObjectEXT);
|
||||
DeclareKindCase(TensorARM);
|
||||
DeclareKindCase(GraphARM);
|
||||
#undef DeclareKindCase
|
||||
@@ -187,6 +188,7 @@ bool Type::operator==(const Type& other) const {
|
||||
DeclareKindCase(CooperativeVectorNV);
|
||||
DeclareKindCase(RayQueryKHR);
|
||||
DeclareKindCase(HitObjectNV);
|
||||
DeclareKindCase(HitObjectEXT);
|
||||
DeclareKindCase(TensorLayoutNV);
|
||||
DeclareKindCase(TensorViewNV);
|
||||
DeclareKindCase(TensorARM);
|
||||
@@ -249,6 +251,7 @@ size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const {
|
||||
DeclareKindCase(CooperativeVectorNV);
|
||||
DeclareKindCase(RayQueryKHR);
|
||||
DeclareKindCase(HitObjectNV);
|
||||
DeclareKindCase(HitObjectEXT);
|
||||
DeclareKindCase(TensorLayoutNV);
|
||||
DeclareKindCase(TensorViewNV);
|
||||
DeclareKindCase(TensorARM);
|
||||
|
||||
4
3rdparty/spirv-tools/source/opt/types.h
vendored
4
3rdparty/spirv-tools/source/opt/types.h
vendored
@@ -67,6 +67,7 @@ class CooperativeMatrixKHR;
|
||||
class CooperativeVectorNV;
|
||||
class RayQueryKHR;
|
||||
class HitObjectNV;
|
||||
class HitObjectEXT;
|
||||
class TensorLayoutNV;
|
||||
class TensorViewNV;
|
||||
class TensorARM;
|
||||
@@ -114,6 +115,7 @@ class Type {
|
||||
kCooperativeVectorNV,
|
||||
kRayQueryKHR,
|
||||
kHitObjectNV,
|
||||
kHitObjectEXT,
|
||||
kTensorLayoutNV,
|
||||
kTensorViewNV,
|
||||
kTensorARM,
|
||||
@@ -222,6 +224,7 @@ class Type {
|
||||
DeclareCastMethod(CooperativeVectorNV)
|
||||
DeclareCastMethod(RayQueryKHR)
|
||||
DeclareCastMethod(HitObjectNV)
|
||||
DeclareCastMethod(HitObjectEXT)
|
||||
DeclareCastMethod(TensorLayoutNV)
|
||||
DeclareCastMethod(TensorViewNV)
|
||||
DeclareCastMethod(TensorARM)
|
||||
@@ -862,6 +865,7 @@ DefineParameterlessType(NamedBarrier, named_barrier);
|
||||
DefineParameterlessType(AccelerationStructureNV, accelerationStructureNV);
|
||||
DefineParameterlessType(RayQueryKHR, rayQueryKHR);
|
||||
DefineParameterlessType(HitObjectNV, hitObjectNV);
|
||||
DefineParameterlessType(HitObjectEXT, hitObjectEXT);
|
||||
#undef DefineParameterlessType
|
||||
|
||||
} // namespace analysis
|
||||
|
||||
@@ -38,6 +38,45 @@ uint32_t ValueNumberTable::GetValueNumber(uint32_t id) const {
|
||||
return GetValueNumber(context()->get_def_use_mgr()->GetDef(id));
|
||||
}
|
||||
|
||||
bool ValueNumberTable::IsReadOnlyLoad(Instruction* inst) {
|
||||
if (!inst->IsLoad()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction* address_def = inst->GetBaseAddress();
|
||||
if (!address_def) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cached_result = read_only_variable_cache_.find(address_def->result_id());
|
||||
if (cached_result != read_only_variable_cache_.end()) {
|
||||
return cached_result->second;
|
||||
}
|
||||
|
||||
bool is_read_only = IsReadOnlyVariable(address_def);
|
||||
read_only_variable_cache_[address_def->result_id()] = is_read_only;
|
||||
return is_read_only;
|
||||
}
|
||||
|
||||
bool ValueNumberTable::IsReadOnlyVariable(Instruction* address_def) {
|
||||
if (address_def->opcode() == spv::Op::OpVariable) {
|
||||
if (address_def->IsReadOnlyPointer()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (address_def->opcode() == spv::Op::OpLoad) {
|
||||
const analysis::Type* address_type =
|
||||
context()->get_type_mgr()->GetType(address_def->type_id());
|
||||
if (address_type->AsSampledImage() != nullptr) {
|
||||
const auto* image_type =
|
||||
address_type->AsSampledImage()->image_type()->AsImage();
|
||||
return image_type->sampled() == 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ValueNumberTable::AssignValueNumber(Instruction* inst) {
|
||||
// If it already has a value return that.
|
||||
uint32_t value = GetValueNumber(inst);
|
||||
@@ -88,7 +127,7 @@ uint32_t ValueNumberTable::AssignValueNumber(Instruction* inst) {
|
||||
// Note that this test will also handle volatile loads because they are not
|
||||
// read only. However, if this is ever relaxed because we analyze stores, we
|
||||
// will have to add a new case for volatile loads.
|
||||
if (inst->IsLoad() && !inst->IsReadOnlyLoad()) {
|
||||
if (inst->IsLoad() && !IsReadOnlyLoad(inst)) {
|
||||
return assign_new_number(inst);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,14 @@ class ValueNumberTable {
|
||||
// Assigns a value number to every result id in the module.
|
||||
void BuildDominatorTreeValueNumberTable();
|
||||
|
||||
// Returns true if |inst| is a load from read-only memory. This is a cached
|
||||
// version of |Instruction::IsReadOnlyLoad| that is local to this pass.
|
||||
bool IsReadOnlyLoad(Instruction* inst);
|
||||
|
||||
// Returns true if the variable pointed to by |address_def| is read-only.
|
||||
// This is the part of |IsReadOnlyLoad| that is cached.
|
||||
bool IsReadOnlyVariable(Instruction* address_def);
|
||||
|
||||
// Returns the new value number.
|
||||
uint32_t TakeNextValueNumber() { return next_value_number_++; }
|
||||
|
||||
@@ -81,6 +89,10 @@ class ValueNumberTable {
|
||||
std::unordered_map<Instruction, uint32_t, ValueTableHash, ComputeSameValue>
|
||||
instruction_to_value_;
|
||||
std::unordered_map<uint32_t, uint32_t> id_to_value_;
|
||||
// A cache for the results of |IsReadOnlyVariable|. The key is the base
|
||||
// variable of a load.
|
||||
std::unordered_map<uint32_t, bool> read_only_variable_cache_;
|
||||
|
||||
IRContext* context_;
|
||||
uint32_t next_value_number_;
|
||||
};
|
||||
|
||||
17
3rdparty/spirv-tools/source/util/bitutils.h
vendored
17
3rdparty/spirv-tools/source/util/bitutils.h
vendored
@@ -206,6 +206,23 @@ T ZeroExtendValue(T value, uint32_t number_of_bits) {
|
||||
return utils::ClearHighBits(value, bit_width - number_of_bits);
|
||||
}
|
||||
|
||||
// Returns the the least significant bit from |value|.
|
||||
template <typename T>
|
||||
constexpr T LSB(T value) {
|
||||
static_assert(std::is_integral<T>::value, "LSB requires integer type");
|
||||
if constexpr (std::is_unsigned_v<T>) {
|
||||
// Prevent warnings about doing a -x on unsigned values.
|
||||
return value & (~value + 1);
|
||||
} else {
|
||||
return value & -value;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(LSB<uint32_t>(UINT32_MAX) == uint32_t(0x00000001), "LSB failed");
|
||||
static_assert(LSB<uint32_t>(0x10001000) == uint32_t(0x00001000), "LSB failed");
|
||||
static_assert(LSB<uint32_t>(0x10000000) == uint32_t(0x10000000), "LSB failed");
|
||||
static_assert(LSB<int32_t>(-1) == int32_t(0x00000001), "LSB failed");
|
||||
|
||||
} // namespace utils
|
||||
} // namespace spvtools
|
||||
|
||||
|
||||
31
3rdparty/spirv-tools/source/util/status.h
vendored
Normal file
31
3rdparty/spirv-tools/source/util/status.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2025 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_UTIL_STATUS_H_
|
||||
#define SOURCE_UTIL_STATUS_H_
|
||||
|
||||
namespace spvtools {
|
||||
namespace utils {
|
||||
|
||||
// The result of processing a module.
|
||||
enum class Status {
|
||||
Failure = 0x0,
|
||||
SuccessWithChange = 0x10,
|
||||
SuccessWithoutChange = 0x11
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_UTIL_STATUS_H_
|
||||
2
3rdparty/spirv-tools/source/val/validate.cpp
vendored
2
3rdparty/spirv-tools/source/val/validate.cpp
vendored
@@ -399,6 +399,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
|
||||
if (auto error = RayQueryPass(*vstate, &instruction)) return error;
|
||||
if (auto error = RayTracingPass(*vstate, &instruction)) return error;
|
||||
if (auto error = RayReorderNVPass(*vstate, &instruction)) return error;
|
||||
if (auto error = RayReorderEXTPass(*vstate, &instruction)) return error;
|
||||
if (auto error = MeshShadingPass(*vstate, &instruction)) return error;
|
||||
if (auto error = TensorLayoutPass(*vstate, &instruction)) return error;
|
||||
if (auto error = TensorPass(*vstate, &instruction)) return error;
|
||||
@@ -430,6 +431,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
|
||||
if (auto error = ValidateQCOMImageProcessingTextureUsages(*vstate, &inst))
|
||||
return error;
|
||||
}
|
||||
if (auto error = ValidateLogicalPointers(*vstate)) return error;
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
6
3rdparty/spirv-tools/source/val/validate.h
vendored
6
3rdparty/spirv-tools/source/val/validate.h
vendored
@@ -220,6 +220,9 @@ spv_result_t RayTracingPass(ValidationState_t& _, const Instruction* inst);
|
||||
/// Validates correctness of shader execution reorder instructions.
|
||||
spv_result_t RayReorderNVPass(ValidationState_t& _, const Instruction* inst);
|
||||
|
||||
/// Validates correctness of shader execution reorder EXT instructions.
|
||||
spv_result_t RayReorderEXTPass(ValidationState_t& _, const Instruction* inst);
|
||||
|
||||
/// Validates correctness of mesh shading instructions.
|
||||
spv_result_t MeshShadingPass(ValidationState_t& _, const Instruction* inst);
|
||||
|
||||
@@ -259,6 +262,9 @@ spv_result_t ValidateSmallTypeUses(ValidationState_t& _,
|
||||
spv_result_t ValidateQCOMImageProcessingTextureUsages(ValidationState_t& _,
|
||||
const Instruction* inst);
|
||||
|
||||
/// Validates logical pointer restrictions.
|
||||
spv_result_t ValidateLogicalPointers(ValidationState_t& _);
|
||||
|
||||
/// @brief Validate the ID's within a SPIR-V binary
|
||||
///
|
||||
/// @param[in] pInstructions array of instructions
|
||||
|
||||
@@ -217,6 +217,7 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec,
|
||||
sc != spv::StorageClass::IncomingCallableDataKHR &&
|
||||
sc != spv::StorageClass::ShaderRecordBufferKHR &&
|
||||
sc != spv::StorageClass::HitObjectAttributeNV &&
|
||||
sc != spv::StorageClass::HitObjectAttributeEXT &&
|
||||
sc != spv::StorageClass::TileImageEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, target)
|
||||
<< _.VkErrorID(6672) << _.SpvDecorationString(dec)
|
||||
|
||||
@@ -36,7 +36,8 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
|
||||
case spv::Op::OpFDiv:
|
||||
case spv::Op::OpFRem:
|
||||
case spv::Op::OpFMod:
|
||||
case spv::Op::OpFNegate: {
|
||||
case spv::Op::OpFNegate:
|
||||
case spv::Op::OpFmaKHR: {
|
||||
bool supportsCoopMat =
|
||||
(opcode != spv::Op::OpFMul && opcode != spv::Op::OpFRem &&
|
||||
opcode != spv::Op::OpFMod);
|
||||
|
||||
@@ -123,7 +123,7 @@ typedef enum VUIDError_ {
|
||||
VUIDErrorMax,
|
||||
} VUIDError;
|
||||
|
||||
const static uint32_t NumVUIDBuiltins = 40;
|
||||
const static uint32_t NumVUIDBuiltins = 41;
|
||||
|
||||
typedef struct {
|
||||
spv::BuiltIn builtIn;
|
||||
@@ -170,6 +170,7 @@ std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
|
||||
{spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}},
|
||||
{spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}},
|
||||
{spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}},
|
||||
{spv::BuiltIn::LocalInvocationIndex, {4284, 4285, 4286}},
|
||||
{spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}},
|
||||
{spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}},
|
||||
{spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
|
||||
@@ -2829,14 +2830,69 @@ spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition(
|
||||
const Decoration& decoration, const Instruction& inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (spv_result_t error = ValidateI32(
|
||||
decoration, inst,
|
||||
[this, &inst](const std::string& message) -> spv_result_t {
|
||||
uint32_t vuid = GetVUIDForBuiltin(
|
||||
spv::BuiltIn::LocalInvocationIndex, VUIDErrorType);
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< _.VkErrorID(vuid)
|
||||
<< "According to the Vulkan spec BuiltIn "
|
||||
"LocalInvocationIndex variable needs to be a 32-bit "
|
||||
"int scalar. "
|
||||
<< message;
|
||||
})) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// Seed at reference checks with this built-in.
|
||||
return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst);
|
||||
}
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference(
|
||||
const Decoration& decoration, const Instruction& built_in_inst,
|
||||
const Instruction&,
|
||||
const Instruction& referenced_inst,
|
||||
const Instruction& referenced_from_inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
const spv::StorageClass storage_class =
|
||||
GetStorageClass(referenced_from_inst);
|
||||
if (storage_class != spv::StorageClass::Max &&
|
||||
storage_class != spv::StorageClass::Input) {
|
||||
uint32_t vuid = GetVUIDForBuiltin(spv::BuiltIn::LocalInvocationIndex,
|
||||
VUIDErrorStorageClass);
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< _.VkErrorID(vuid)
|
||||
<< "Vulkan spec allows BuiltIn LocalInvocationIndex to be only "
|
||||
"used for variables with Input storage class. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst)
|
||||
<< " " << GetStorageClassDesc(referenced_from_inst);
|
||||
}
|
||||
|
||||
for (const spv::ExecutionModel execution_model : execution_models_) {
|
||||
bool has_vulkan_model =
|
||||
execution_model == spv::ExecutionModel::GLCompute ||
|
||||
execution_model == spv::ExecutionModel::TaskNV ||
|
||||
execution_model == spv::ExecutionModel::MeshNV ||
|
||||
execution_model == spv::ExecutionModel::TaskEXT ||
|
||||
execution_model == spv::ExecutionModel::MeshEXT;
|
||||
|
||||
if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
|
||||
uint32_t vuid = GetVUIDForBuiltin(spv::BuiltIn::LocalInvocationIndex,
|
||||
VUIDErrorExecutionModel);
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< _.VkErrorID(vuid)
|
||||
<< "Vulkan spec allows BuiltIn LocalInvocationIndex to be used "
|
||||
"only with GLCompute, MeshNV, TaskNV, MeshEXT or"
|
||||
<< " TaskEXT execution model. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst, execution_model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (function_id_ == 0) {
|
||||
// Propagate this rule to all dependant ids in the global scope.
|
||||
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
|
||||
|
||||
@@ -532,8 +532,7 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _,
|
||||
if (!resultType || resultType->opcode() != spv::Op::OpTypeVector) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Result Type of OpVectorShuffle must be"
|
||||
<< " OpTypeVector. Found Op"
|
||||
<< spvOpcodeString(static_cast<spv::Op>(resultType->opcode()))
|
||||
<< " OpTypeVector. Found Op" << spvOpcodeString(resultType->opcode())
|
||||
<< ".";
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
// Validates correctness of extension SPIR-V instructions.
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -1087,6 +1088,7 @@ spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
|
||||
ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout) ||
|
||||
extension == ExtensionToString(kSPV_EXT_mesh_shader) ||
|
||||
extension == ExtensionToString(kSPV_NV_shader_invocation_reorder) ||
|
||||
extension == ExtensionToString(kSPV_EXT_shader_invocation_reorder) ||
|
||||
extension ==
|
||||
ExtensionToString(kSPV_NV_cluster_acceleration_structure) ||
|
||||
extension == ExtensionToString(kSPV_NV_linear_swept_spheres) ||
|
||||
@@ -3753,12 +3755,26 @@ spv_result_t ValidateExtInstDebugInfo100(ValidationState_t& _,
|
||||
},
|
||||
inst, 12)) {
|
||||
auto* operand = _.FindDef(inst->word(12));
|
||||
if (operand->opcode() != spv::Op::OpVariable &&
|
||||
operand->opcode() != spv::Op::OpConstant) {
|
||||
std::initializer_list<spv::Op> allowed_opcodes = {
|
||||
spv::Op::OpVariable,
|
||||
spv::Op::OpConstantTrue,
|
||||
spv::Op::OpConstantFalse,
|
||||
spv::Op::OpConstant,
|
||||
spv::Op::OpConstantComposite,
|
||||
spv::Op::OpConstantSampler,
|
||||
spv::Op::OpConstantNull,
|
||||
spv::Op::OpSpecConstantTrue,
|
||||
spv::Op::OpSpecConstantFalse,
|
||||
spv::Op::OpSpecConstant,
|
||||
spv::Op::OpSpecConstantComposite,
|
||||
spv::Op::OpSpecConstantOp};
|
||||
if (std::find(allowed_opcodes.begin(), allowed_opcodes.end(),
|
||||
operand->opcode()) == allowed_opcodes.end()) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< GetExtInstName(_, inst) << ": "
|
||||
<< "expected operand Variable must be a result id of "
|
||||
"OpVariable or OpConstant or DebugInfoNone";
|
||||
"OpVariable, OpConstant variant, OpSpecConstant variant "
|
||||
"or DebugInfoNone";
|
||||
}
|
||||
}
|
||||
if (num_words == 15) {
|
||||
|
||||
@@ -170,6 +170,34 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _,
|
||||
<< "s type does not match Function <id> "
|
||||
<< _.getIdName(return_type->id()) << "s return type.";
|
||||
}
|
||||
if (!_.options()->relax_logical_pointer &&
|
||||
(_.addressing_model() == spv::AddressingModel::Logical ||
|
||||
_.addressing_model() == spv::AddressingModel::PhysicalStorageBuffer64)) {
|
||||
if (return_type->opcode() == spv::Op::OpTypePointer ||
|
||||
return_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
|
||||
const auto sc = return_type->GetOperandAs<spv::StorageClass>(1);
|
||||
if (sc != spv::StorageClass::PhysicalStorageBuffer) {
|
||||
if (!_.HasCapability(spv::Capability::VariablePointersStorageBuffer) &&
|
||||
sc == spv::StorageClass::StorageBuffer) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, functions may only return a "
|
||||
"storage buffer pointer if the "
|
||||
"VariablePointersStorageBuffer capability is declared";
|
||||
} else if (!_.HasCapability(spv::Capability::VariablePointers) &&
|
||||
sc == spv::StorageClass::Workgroup) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, functions may only return a "
|
||||
"workgroup pointer if the VariablePointers capability is "
|
||||
"declared";
|
||||
} else if (sc != spv::StorageClass::StorageBuffer &&
|
||||
sc != spv::StorageClass::Workgroup) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, functions may not return a pointer "
|
||||
"in this storage class";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto function_type_id = function->GetOperandAs<uint32_t>(3);
|
||||
const auto function_type = _.FindDef(function_type_id);
|
||||
@@ -216,51 +244,59 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _,
|
||||
}
|
||||
}
|
||||
|
||||
if (_.addressing_model() == spv::AddressingModel::Logical) {
|
||||
if (_.addressing_model() == spv::AddressingModel::Logical ||
|
||||
_.addressing_model() == spv::AddressingModel::PhysicalStorageBuffer64) {
|
||||
if ((parameter_type->opcode() == spv::Op::OpTypePointer ||
|
||||
parameter_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) &&
|
||||
!_.options()->relax_logical_pointer) {
|
||||
spv::StorageClass sc =
|
||||
parameter_type->GetOperandAs<spv::StorageClass>(1u);
|
||||
// Validate which storage classes can be pointer operands.
|
||||
switch (sc) {
|
||||
case spv::StorageClass::UniformConstant:
|
||||
case spv::StorageClass::Function:
|
||||
case spv::StorageClass::Private:
|
||||
case spv::StorageClass::Workgroup:
|
||||
case spv::StorageClass::AtomicCounter:
|
||||
// These are always allowed.
|
||||
break;
|
||||
case spv::StorageClass::StorageBuffer:
|
||||
if (!_.features().variable_pointers) {
|
||||
if (sc != spv::StorageClass::PhysicalStorageBuffer) {
|
||||
// Validate which storage classes can be pointer operands.
|
||||
switch (sc) {
|
||||
case spv::StorageClass::UniformConstant:
|
||||
case spv::StorageClass::Function:
|
||||
case spv::StorageClass::Private:
|
||||
case spv::StorageClass::Workgroup:
|
||||
case spv::StorageClass::AtomicCounter:
|
||||
// SPV_EXT_tile_image
|
||||
case spv::StorageClass::TileImageEXT:
|
||||
// SPV_KHR_ray_tracing
|
||||
case spv::StorageClass::ShaderRecordBufferKHR:
|
||||
// These are always allowed.
|
||||
break;
|
||||
case spv::StorageClass::StorageBuffer:
|
||||
if (!_.features().variable_pointers) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "StorageBuffer pointer operand "
|
||||
<< _.getIdName(argument_id)
|
||||
<< " requires a variable pointers capability";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "StorageBuffer pointer operand "
|
||||
<< _.getIdName(argument_id)
|
||||
<< " requires a variable pointers capability";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Invalid storage class for pointer operand "
|
||||
<< _.getIdName(argument_id);
|
||||
}
|
||||
<< "Invalid storage class for pointer operand "
|
||||
<< _.getIdName(argument_id);
|
||||
}
|
||||
|
||||
// Validate memory object declaration requirements.
|
||||
if (argument->opcode() != spv::Op::OpVariable &&
|
||||
argument->opcode() != spv::Op::OpUntypedVariableKHR &&
|
||||
argument->opcode() != spv::Op::OpFunctionParameter) {
|
||||
const bool ssbo_vptr =
|
||||
_.HasCapability(spv::Capability::VariablePointersStorageBuffer) &&
|
||||
sc == spv::StorageClass::StorageBuffer;
|
||||
const bool wg_vptr =
|
||||
_.HasCapability(spv::Capability::VariablePointers) &&
|
||||
sc == spv::StorageClass::Workgroup;
|
||||
const bool uc_ptr = sc == spv::StorageClass::UniformConstant;
|
||||
if (!_.options()->before_hlsl_legalization && !ssbo_vptr &&
|
||||
!wg_vptr && !uc_ptr) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Pointer operand " << _.getIdName(argument_id)
|
||||
<< " must be a memory object declaration";
|
||||
// Validate memory object declaration requirements.
|
||||
if (argument->opcode() != spv::Op::OpVariable &&
|
||||
argument->opcode() != spv::Op::OpUntypedVariableKHR &&
|
||||
argument->opcode() != spv::Op::OpFunctionParameter) {
|
||||
const bool ssbo_vptr =
|
||||
_.HasCapability(
|
||||
spv::Capability::VariablePointersStorageBuffer) &&
|
||||
sc == spv::StorageClass::StorageBuffer;
|
||||
const bool wg_vptr =
|
||||
_.HasCapability(spv::Capability::VariablePointers) &&
|
||||
sc == spv::StorageClass::Workgroup;
|
||||
const bool uc_ptr = sc == spv::StorageClass::UniformConstant;
|
||||
if (!_.options()->before_hlsl_legalization && !ssbo_vptr &&
|
||||
!wg_vptr && !uc_ptr) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Pointer operand " << _.getIdName(argument_id)
|
||||
<< " must be a memory object declaration";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,7 +1100,7 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
|
||||
<< "Result <id> from OpSampledImage instruction must not appear "
|
||||
"as "
|
||||
"operands of Op"
|
||||
<< spvOpcodeString(static_cast<spv::Op>(consumer_opcode)) << "."
|
||||
<< spvOpcodeString(consumer_opcode) << "."
|
||||
<< " Found result <id> " << _.getIdName(inst->id())
|
||||
<< " as an operand of <id> " << _.getIdName(consumer_instr->id())
|
||||
<< ".";
|
||||
@@ -1110,12 +1110,11 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Result <id> from OpSampledImage instruction must not appear "
|
||||
"as operand for Op"
|
||||
<< spvOpcodeString(static_cast<spv::Op>(consumer_opcode))
|
||||
<< spvOpcodeString(consumer_opcode)
|
||||
<< ", since it is not specified as taking an "
|
||||
<< "OpTypeSampledImage."
|
||||
<< " Found result <id> " << _.getIdName(inst->id())
|
||||
<< " as an operand of <id> " << _.getIdName(consumer_instr->id())
|
||||
<< ".";
|
||||
<< "OpTypeSampledImage." << " Found result <id> "
|
||||
<< _.getIdName(inst->id()) << " as an operand of <id> "
|
||||
<< _.getIdName(consumer_instr->id()) << ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1010
3rdparty/spirv-tools/source/val/validate_logical_pointers.cpp
vendored
Normal file
1010
3rdparty/spirv-tools/source/val/validate_logical_pointers.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
360
3rdparty/spirv-tools/source/val/validate_memory.cpp
vendored
360
3rdparty/spirv-tools/source/val/validate_memory.cpp
vendored
@@ -515,6 +515,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
storage_class != spv::StorageClass::IncomingCallableDataKHR &&
|
||||
storage_class != spv::StorageClass::TaskPayloadWorkgroupEXT &&
|
||||
storage_class != spv::StorageClass::HitObjectAttributeNV &&
|
||||
storage_class != spv::StorageClass::HitObjectAttributeEXT &&
|
||||
storage_class != spv::StorageClass::NodePayloadAMDX) {
|
||||
bool storage_input_or_output = storage_class == spv::StorageClass::Input ||
|
||||
storage_class == spv::StorageClass::Output;
|
||||
@@ -586,20 +587,38 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
const auto pointee = untyped_pointer
|
||||
? value_id == 0 ? nullptr : _.FindDef(value_id)
|
||||
: _.FindDef(result_type->word(3));
|
||||
if (_.addressing_model() == spv::AddressingModel::Logical &&
|
||||
if ((_.addressing_model() == spv::AddressingModel::Logical ||
|
||||
_.addressing_model() == spv::AddressingModel::PhysicalStorageBuffer64) &&
|
||||
!_.options()->relax_logical_pointer) {
|
||||
// VariablePointersStorageBuffer is implied by VariablePointers.
|
||||
if (pointee && pointee->opcode() == spv::Op::OpTypePointer) {
|
||||
if (!_.HasCapability(spv::Capability::VariablePointersStorageBuffer)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, variables may not allocate a pointer "
|
||||
<< "type";
|
||||
} else if (storage_class != spv::StorageClass::Function &&
|
||||
storage_class != spv::StorageClass::Private) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing with variable pointers, variables "
|
||||
<< "that allocate pointers must be in Function or Private "
|
||||
<< "storage classes";
|
||||
if (pointee && (pointee->opcode() == spv::Op::OpTypePointer ||
|
||||
pointee->opcode() == spv::Op::OpTypeUntypedPointerKHR)) {
|
||||
const auto sc = pointee->GetOperandAs<spv::StorageClass>(1u);
|
||||
if (sc != spv::StorageClass::PhysicalStorageBuffer) {
|
||||
if (sc != spv::StorageClass::StorageBuffer &&
|
||||
sc != spv::StorageClass::Workgroup) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, variables can only allocate a "
|
||||
"pointer to the StorageBuffer or Workgroup storage classes";
|
||||
} else if (!_.HasCapability(
|
||||
spv::Capability::VariablePointersStorageBuffer) &&
|
||||
sc == spv::StorageClass::StorageBuffer) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, variables can only allocate a "
|
||||
"storage buffer pointer if the "
|
||||
"VariablePointersStorageBuffer capability is declared";
|
||||
} else if (!_.HasCapability(spv::Capability::VariablePointers) &&
|
||||
sc == spv::StorageClass::Workgroup) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing, variables can only allocate a "
|
||||
"workgroup pointer if the VariablePointers capability is "
|
||||
"declared";
|
||||
} else if (storage_class != spv::StorageClass::Function &&
|
||||
storage_class != spv::StorageClass::Private) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Logical addressing with variable pointers, variables "
|
||||
<< "that allocate pointers must be in Function or Private "
|
||||
<< "storage classes";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -738,6 +757,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
<< "OpVariable, <id> " << _.getIdName(inst->id())
|
||||
<< ", initializer are not allowed for HitObjectAttributeNV";
|
||||
}
|
||||
if (storage_class == spv::StorageClass::HitObjectAttributeEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> " << _.getIdName(inst->id())
|
||||
<< ", initializer are not allowed for HitObjectAttributeEXT";
|
||||
}
|
||||
}
|
||||
|
||||
if (storage_class == spv::StorageClass::PhysicalStorageBuffer) {
|
||||
@@ -776,8 +800,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
|
||||
// If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it
|
||||
// must either have the storage class StorageBuffer and be decorated
|
||||
// with Block, or it must be in the Uniform storage class and be decorated
|
||||
// as BufferBlock.
|
||||
// with Block, or it must be in the Uniform storage class
|
||||
if (value_type && value_type->opcode() == spv::Op::OpTypeStruct) {
|
||||
if (DoesStructContainRTA(_, value_type)) {
|
||||
if (storage_class == spv::StorageClass::StorageBuffer ||
|
||||
@@ -791,13 +814,14 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
"PhysicalStorageBuffer.";
|
||||
}
|
||||
} else if (storage_class == spv::StorageClass::Uniform) {
|
||||
if (!_.HasDecoration(value_id, spv::Decoration::BufferBlock)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< _.VkErrorID(4680)
|
||||
<< "For Vulkan, an OpTypeStruct variable containing an "
|
||||
<< "OpTypeRuntimeArray must be decorated with BufferBlock "
|
||||
<< "if it has storage class Uniform.";
|
||||
}
|
||||
// BufferBlock Uniform were always allowed.
|
||||
//
|
||||
// Block Uniform use to be invalid, but Vulkan added
|
||||
// VK_EXT_shader_uniform_buffer_unsized_array and now this is
|
||||
// validated at runtime
|
||||
//
|
||||
// The uniform must have either the Block or BufferBlock decoration
|
||||
// (see VUID-StandaloneSpirv-Uniform-06676)
|
||||
} else {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< _.VkErrorID(4680)
|
||||
@@ -1299,7 +1323,7 @@ spv_result_t ValidateCopyMemoryMemoryAccess(ValidationState_t& _,
|
||||
}
|
||||
} else {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< spvOpcodeString(static_cast<spv::Op>(inst->opcode()))
|
||||
<< spvOpcodeString(inst->opcode())
|
||||
<< " with two memory access operands requires SPIR-V 1.4 or "
|
||||
"later";
|
||||
}
|
||||
@@ -1551,9 +1575,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) {
|
||||
|
||||
spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
std::string instr_name =
|
||||
"Op" + std::string(spvOpcodeString(static_cast<spv::Op>(inst->opcode())));
|
||||
|
||||
const spv::Op opcode = inst->opcode();
|
||||
const bool untyped_pointer = spvOpcodeGeneratesUntypedPointer(inst->opcode());
|
||||
|
||||
// The result type must be OpTypePointer for regular access chains and an
|
||||
@@ -1563,19 +1585,17 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
if (!result_type ||
|
||||
spv::Op::OpTypeUntypedPointerKHR != result_type->opcode()) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id())
|
||||
<< " must be OpTypeUntypedPointerKHR. Found Op"
|
||||
<< spvOpcodeString(static_cast<spv::Op>(result_type->opcode()))
|
||||
<< ".";
|
||||
<< spvOpcodeString(result_type->opcode()) << ".";
|
||||
}
|
||||
} else {
|
||||
if (!result_type || spv::Op::OpTypePointer != result_type->opcode()) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id()) << " must be OpTypePointer. Found Op"
|
||||
<< spvOpcodeString(static_cast<spv::Op>(result_type->opcode()))
|
||||
<< ".";
|
||||
<< spvOpcodeString(result_type->opcode()) << ".";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1653,8 +1673,8 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
(untyped_pointer && spv::Op::OpTypeUntypedPointerKHR ==
|
||||
base_type->opcode()))) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Base <id> " << _.getIdName(base_id) << " in " << instr_name
|
||||
<< " instruction must be a pointer.";
|
||||
<< "The Base <id> " << _.getIdName(base_id) << " in Op"
|
||||
<< spvOpcodeString(opcode) << " instruction must be a pointer.";
|
||||
}
|
||||
|
||||
// The result pointer storage class and base pointer storage class must match.
|
||||
@@ -1664,8 +1684,8 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
if (result_type_storage_class != base_type_storage_class) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The result pointer storage class and base "
|
||||
"pointer storage class in "
|
||||
<< instr_name << " do not match.";
|
||||
"pointer storage class in Op"
|
||||
<< spvOpcodeString(opcode) << " do not match.";
|
||||
}
|
||||
|
||||
// The type pointed to by OpTypePointer (word 3) must be a composite type.
|
||||
@@ -1689,8 +1709,9 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
_.options()->universal_limits_.max_access_chain_indexes;
|
||||
if (num_indexes > num_indexes_limit) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The number of indexes in " << instr_name << " may not exceed "
|
||||
<< num_indexes_limit << ". Found " << num_indexes << " indexes.";
|
||||
<< "The number of indexes in Op" << spvOpcodeString(opcode)
|
||||
<< " may not exceed " << num_indexes_limit << ". Found "
|
||||
<< num_indexes << " indexes.";
|
||||
}
|
||||
// Indexes walk the type hierarchy to the desired depth, potentially down to
|
||||
// scalar granularity. The first index in Indexes will select the top-level
|
||||
@@ -1714,9 +1735,29 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
auto index_type = _.FindDef(cur_word_instr->type_id());
|
||||
if (!index_type || spv::Op::OpTypeInt != index_type->opcode()) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Indexes passed to " << instr_name
|
||||
<< "Indexes passed to Op" << spvOpcodeString(opcode)
|
||||
<< " must be of type integer.";
|
||||
}
|
||||
|
||||
// Logical pointer restrictions: any constant index with a signed integer
|
||||
// type must not have its sign bit set.
|
||||
if (!_.options()->relax_logical_pointer &&
|
||||
(_.addressing_model() == spv::AddressingModel::Logical ||
|
||||
_.addressing_model() ==
|
||||
spv::AddressingModel::PhysicalStorageBuffer64) &&
|
||||
result_type_storage_class !=
|
||||
static_cast<uint32_t>(spv::StorageClass::PhysicalStorageBuffer)) {
|
||||
if (index_type->GetOperandAs<uint32_t>(2) == 1) {
|
||||
int64_t val = 0;
|
||||
if (_.EvalConstantValInt64(cur_word, &val)) {
|
||||
if (val < 0) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Index at word " << i << " may not have a negative value";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (type_pointee->opcode()) {
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
@@ -1738,8 +1779,8 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
int64_t cur_index;
|
||||
if (!_.EvalConstantValInt64(cur_word, &cur_index)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The <id> passed to " << instr_name << " to index "
|
||||
<< _.getIdName(cur_word)
|
||||
<< "The <id> passed to Op" << spvOpcodeString(opcode)
|
||||
<< " to index " << _.getIdName(cur_word)
|
||||
<< " into a "
|
||||
"structure must be an OpConstant.";
|
||||
}
|
||||
@@ -1750,8 +1791,8 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
static_cast<int64_t>(type_pointee->words().size() - 2);
|
||||
if (cur_index >= num_struct_members || cur_index < 0) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Index " << _.getIdName(cur_word)
|
||||
<< " is out of bounds: " << instr_name << " cannot find index "
|
||||
<< "Index " << _.getIdName(cur_word) << " is out of bounds: Op"
|
||||
<< spvOpcodeString(opcode) << " cannot find index "
|
||||
<< cur_index << " into the structure <id> "
|
||||
<< _.getIdName(type_pointee->id()) << ". This structure has "
|
||||
<< num_struct_members << " members. Largest valid index is "
|
||||
@@ -1766,7 +1807,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
default: {
|
||||
// Give an error. reached non-composite type while indexes still remain.
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< instr_name
|
||||
<< "Op" << spvOpcodeString(opcode)
|
||||
<< " reached non-composite type while indexes "
|
||||
"still remain to be traversed.";
|
||||
}
|
||||
@@ -1782,14 +1823,12 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
// The type being pointed to should be the same as the result type.
|
||||
if (type_pointee->id() != result_type_pointee->id()) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< instr_name << " result type (Op"
|
||||
<< spvOpcodeString(
|
||||
static_cast<spv::Op>(result_type_pointee->opcode()))
|
||||
<< "Op" << spvOpcodeString(opcode) << " result type (Op"
|
||||
<< spvOpcodeString(result_type_pointee->opcode())
|
||||
<< ") does not match the type that results from indexing into the "
|
||||
"base "
|
||||
"<id> (Op"
|
||||
<< spvOpcodeString(static_cast<spv::Op>(type_pointee->opcode()))
|
||||
<< ").";
|
||||
<< spvOpcodeString(type_pointee->opcode()) << ").";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1798,13 +1837,12 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
|
||||
|
||||
spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
std::string instr_name = "Op" + std::string(spvOpcodeString(inst->opcode()));
|
||||
|
||||
const spv::Op opcode = inst->opcode();
|
||||
// The result type must be OpTypePointer.
|
||||
const auto result_type = _.FindDef(inst->type_id());
|
||||
if (spv::Op::OpTypePointer != result_type->opcode()) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id()) << " must be OpTypePointer. Found Op"
|
||||
<< spvOpcodeString(result_type->opcode()) << '.';
|
||||
}
|
||||
@@ -1815,7 +1853,7 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
storage_class != spv::StorageClass::PhysicalStorageBuffer &&
|
||||
storage_class != spv::StorageClass::Uniform) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id())
|
||||
<< " must point to a storage class of "
|
||||
"StorageBuffer, PhysicalStorageBuffer, or Uniform.";
|
||||
@@ -1828,7 +1866,7 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
result_type_pointee->opcode() == spv::Op::OpTypeMatrix ||
|
||||
result_type_pointee->opcode() == spv::Op::OpTypeStruct) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id())
|
||||
<< " must not point to "
|
||||
"OpTypeArray, OpTypeMatrix, or OpTypeStruct.";
|
||||
@@ -1838,7 +1876,7 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
const auto stride = _.FindDef(inst->GetOperandAs<uint32_t>(3));
|
||||
if (stride->opcode() != spv::Op::OpConstant) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The Stride of " << instr_name << " <id> "
|
||||
<< "The Stride of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id()) << " must be OpConstant. Found Op"
|
||||
<< spvOpcodeString(stride->opcode()) << '.';
|
||||
}
|
||||
@@ -1846,7 +1884,7 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
const auto stride_type = _.FindDef(stride->type_id());
|
||||
if (stride_type->opcode() != spv::Op::OpTypeInt) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The type of Stride of " << instr_name << " <id> "
|
||||
<< "The type of Stride of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< _.getIdName(inst->id()) << " must be OpTypeInt. Found Op"
|
||||
<< spvOpcodeString(stride_type->opcode()) << '.';
|
||||
}
|
||||
@@ -1858,16 +1896,17 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
const auto value_type = _.FindDef(value->type_id());
|
||||
if (value_type->opcode() != spv::Op::OpTypeInt) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The type of " << name << " of " << instr_name << " <id> "
|
||||
<< _.getIdName(inst->id()) << " must be OpTypeInt. Found Op"
|
||||
<< "The type of " << name << " of Op" << spvOpcodeString(opcode)
|
||||
<< " <id> " << _.getIdName(inst->id())
|
||||
<< " must be OpTypeInt. Found Op"
|
||||
<< spvOpcodeString(value_type->opcode()) << '.';
|
||||
}
|
||||
const auto width = value_type->GetOperandAs<uint32_t>(1);
|
||||
if (width != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "The integer width of " << name << " of " << instr_name
|
||||
<< " <id> " << _.getIdName(inst->id()) << " must be 32. Found "
|
||||
<< width << '.';
|
||||
<< "The integer width of " << name << " of Op"
|
||||
<< spvOpcodeString(opcode) << " <id> " << _.getIdName(inst->id())
|
||||
<< " must be 32. Found " << width << '.';
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
};
|
||||
@@ -1918,15 +1957,6 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _,
|
||||
|
||||
spv_result_t ValidatePtrAccessChain(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
if (_.addressing_model() == spv::AddressingModel::Logical &&
|
||||
inst->opcode() == spv::Op::OpPtrAccessChain) {
|
||||
if (!_.features().variable_pointers) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Generating variable pointers requires capability "
|
||||
<< "VariablePointers or VariablePointersStorageBuffer";
|
||||
}
|
||||
}
|
||||
|
||||
// Need to call first, will make sure Base is a valid ID
|
||||
if (auto error = ValidateAccessChain(_, inst)) return error;
|
||||
|
||||
@@ -2006,18 +2036,20 @@ spv_result_t ValidatePtrAccessChain(ValidationState_t& _,
|
||||
|
||||
spv_result_t ValidateArrayLength(ValidationState_t& state,
|
||||
const Instruction* inst) {
|
||||
std::string instr_name =
|
||||
"Op" + std::string(spvOpcodeString(static_cast<spv::Op>(inst->opcode())));
|
||||
const spv::Op opcode = inst->opcode();
|
||||
|
||||
// Result type must be a 32-bit unsigned int.
|
||||
// Result type must be a 32- or 64-bit unsigned int.
|
||||
// 64-bit requires CapabilityShader64BitIndexingEXT or a pipeline/shader
|
||||
// flag and is validated in VVL.
|
||||
auto result_type = state.FindDef(inst->type_id());
|
||||
if (result_type->opcode() != spv::Op::OpTypeInt ||
|
||||
result_type->GetOperandAs<uint32_t>(1) != 32 ||
|
||||
!(result_type->GetOperandAs<uint32_t>(1) == 32 ||
|
||||
result_type->GetOperandAs<uint32_t>(1) == 64) ||
|
||||
result_type->GetOperandAs<uint32_t>(2) != 0) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< state.getIdName(inst->id())
|
||||
<< " must be OpTypeInt with width 32 and signedness 0.";
|
||||
<< " must be OpTypeInt with width 32 or 64 and signedness 0.";
|
||||
}
|
||||
|
||||
const bool untyped = inst->opcode() == spv::Op::OpUntypedArrayLengthKHR;
|
||||
@@ -2030,8 +2062,8 @@ spv_result_t ValidateArrayLength(ValidationState_t& state,
|
||||
}
|
||||
} else if (pointer_ty->opcode() != spv::Op::OpTypePointer) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Structure's type in " << instr_name << " <id> "
|
||||
<< state.getIdName(inst->id())
|
||||
<< "The Structure's type in Op" << spvOpcodeString(opcode)
|
||||
<< " <id> " << state.getIdName(inst->id())
|
||||
<< " must be a pointer to an OpTypeStruct.";
|
||||
}
|
||||
|
||||
@@ -2044,8 +2076,8 @@ spv_result_t ValidateArrayLength(ValidationState_t& state,
|
||||
|
||||
if (structure_type->opcode() != spv::Op::OpTypeStruct) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Structure's type in " << instr_name << " <id> "
|
||||
<< state.getIdName(inst->id())
|
||||
<< "The Structure's type in Op" << spvOpcodeString(opcode)
|
||||
<< " <id> " << state.getIdName(inst->id())
|
||||
<< " must be a pointer to an OpTypeStruct.";
|
||||
}
|
||||
|
||||
@@ -2054,8 +2086,9 @@ spv_result_t ValidateArrayLength(ValidationState_t& state,
|
||||
state.FindDef(structure_type->GetOperandAs<uint32_t>(num_of_members));
|
||||
if (last_member->opcode() != spv::Op::OpTypeRuntimeArray) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Structure's last member in " << instr_name << " <id> "
|
||||
<< state.getIdName(inst->id()) << " must be an OpTypeRuntimeArray.";
|
||||
<< "The Structure's last member in Op" << spvOpcodeString(opcode)
|
||||
<< " <id> " << state.getIdName(inst->id())
|
||||
<< " must be an OpTypeRuntimeArray.";
|
||||
}
|
||||
|
||||
// The array member must the index of the last element (the run time
|
||||
@@ -2063,25 +2096,35 @@ spv_result_t ValidateArrayLength(ValidationState_t& state,
|
||||
const auto index = untyped ? 4 : 3;
|
||||
if (inst->GetOperandAs<uint32_t>(index) != num_of_members - 1) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The array member in " << instr_name << " <id> "
|
||||
<< "The array member in Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< state.getIdName(inst->id())
|
||||
<< " must be the last member of the struct.";
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(state.context()->target_env)) {
|
||||
const auto storage_class = pointer_ty->GetOperandAs<spv::StorageClass>(1);
|
||||
if (storage_class == spv::StorageClass::Uniform &&
|
||||
state.HasDecoration(structure_type->id(), spv::Decoration::Block)) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< state.VkErrorID(11805) << "Op" << spvOpcodeString(opcode)
|
||||
<< " must not be used on the OpTypeRuntimeArray inside a Uniform "
|
||||
"block";
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateCooperativeMatrixLengthNV(ValidationState_t& state,
|
||||
const Instruction* inst) {
|
||||
std::string instr_name =
|
||||
"Op" + std::string(spvOpcodeString(static_cast<spv::Op>(inst->opcode())));
|
||||
|
||||
const spv::Op opcode = inst->opcode();
|
||||
// Result type must be a 32-bit unsigned int.
|
||||
auto result_type = state.FindDef(inst->type_id());
|
||||
if (result_type->opcode() != spv::Op::OpTypeInt ||
|
||||
result_type->GetOperandAs<uint32_t>(1) != 32 ||
|
||||
result_type->GetOperandAs<uint32_t>(2) != 0) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Result Type of " << instr_name << " <id> "
|
||||
<< "The Result Type of Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< state.getIdName(inst->id())
|
||||
<< " must be OpTypeInt with width 32 and signedness 0.";
|
||||
}
|
||||
@@ -2091,12 +2134,12 @@ spv_result_t ValidateCooperativeMatrixLengthNV(ValidationState_t& state,
|
||||
auto type = state.FindDef(type_id);
|
||||
if (isKhr && type->opcode() != spv::Op::OpTypeCooperativeMatrixKHR) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The type in " << instr_name << " <id> "
|
||||
<< "The type in Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< state.getIdName(type_id)
|
||||
<< " must be OpTypeCooperativeMatrixKHR.";
|
||||
} else if (!isKhr && type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) {
|
||||
return state.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The type in " << instr_name << " <id> "
|
||||
<< "The type in Op" << spvOpcodeString(opcode) << " <id> "
|
||||
<< state.getIdName(type_id) << " must be OpTypeCooperativeMatrixNV.";
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
@@ -2299,23 +2342,96 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _,
|
||||
}
|
||||
|
||||
bool stride_required = false;
|
||||
bool layout_requires_constant_stride = false;
|
||||
uint64_t layout;
|
||||
if (_.EvalConstantValUint64(layout_id, &layout)) {
|
||||
const bool is_arm_layout =
|
||||
(layout ==
|
||||
(uint64_t)spv::CooperativeMatrixLayout::RowBlockedInterleavedARM) ||
|
||||
(layout ==
|
||||
(uint64_t)spv::CooperativeMatrixLayout::ColumnBlockedInterleavedARM);
|
||||
|
||||
if (is_arm_layout) {
|
||||
if (!_.HasCapability(spv::Capability::CooperativeMatrixLayoutsARM)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Using the RowBlockedInterleavedARM or "
|
||||
"ColumnBlockedInterleavedARM MemoryLayout requires the "
|
||||
"CooperativeMatrixLayoutsARM capability be declared";
|
||||
}
|
||||
}
|
||||
|
||||
stride_required =
|
||||
(layout == (uint64_t)spv::CooperativeMatrixLayout::RowMajorKHR) ||
|
||||
(layout == (uint64_t)spv::CooperativeMatrixLayout::ColumnMajorKHR);
|
||||
(layout == (uint64_t)spv::CooperativeMatrixLayout::ColumnMajorKHR) ||
|
||||
is_arm_layout;
|
||||
layout_requires_constant_stride = is_arm_layout;
|
||||
}
|
||||
|
||||
const auto stride_index =
|
||||
(inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 4u : 3u;
|
||||
if (inst->operands().size() > stride_index) {
|
||||
const auto stride_id = inst->GetOperandAs<uint32_t>(stride_index);
|
||||
const auto stride = _.FindDef(stride_id);
|
||||
if (!stride || !_.IsIntScalarType(stride->type_id())) {
|
||||
const auto stride_inst = _.FindDef(stride_id);
|
||||
if (!stride_inst || !_.IsIntScalarType(stride_inst->type_id())) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Stride operand <id> " << _.getIdName(stride_id)
|
||||
<< " must be a scalar integer type.";
|
||||
}
|
||||
// Check SPV_ARM_cooperative_matrix_layouts constraints
|
||||
if (layout_requires_constant_stride &&
|
||||
!spvOpcodeIsConstant(stride_inst->opcode())) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "MemoryLayout " << layout
|
||||
<< " requires Stride come from a constant instruction.";
|
||||
}
|
||||
if (layout_requires_constant_stride) {
|
||||
uint64_t stride;
|
||||
if (_.EvalConstantValUint64(stride_id, &stride)) {
|
||||
if ((layout ==
|
||||
(uint64_t)
|
||||
spv::CooperativeMatrixLayout::RowBlockedInterleavedARM) ||
|
||||
(layout ==
|
||||
(uint64_t)
|
||||
spv::CooperativeMatrixLayout::ColumnBlockedInterleavedARM)) {
|
||||
if ((stride != 1) && (stride != 2) && (stride != 4)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "MemoryLayout " << layout
|
||||
<< " requires Stride be 1, 2, or 4.";
|
||||
}
|
||||
}
|
||||
const uint32_t elty_id = matrix_type->GetOperandAs<uint32_t>(1);
|
||||
const uint32_t rows_id = matrix_type->GetOperandAs<uint32_t>(3);
|
||||
const uint32_t cols_id = matrix_type->GetOperandAs<uint32_t>(4);
|
||||
uint64_t rows = 0, cols = 0;
|
||||
_.EvalConstantValUint64(rows_id, &rows);
|
||||
_.EvalConstantValUint64(cols_id, &cols);
|
||||
uint32_t sizeof_component_in_bytes = _.GetBitWidth(elty_id) / 8;
|
||||
uint64_t rows_required_multiple = 4;
|
||||
uint64_t cols_required_multiple = 16 / sizeof_component_in_bytes;
|
||||
|
||||
if (layout ==
|
||||
(uint64_t)spv::CooperativeMatrixLayout::RowBlockedInterleavedARM) {
|
||||
cols_required_multiple *= stride;
|
||||
}
|
||||
if (layout ==
|
||||
(uint64_t)
|
||||
spv::CooperativeMatrixLayout::ColumnBlockedInterleavedARM) {
|
||||
rows_required_multiple *= stride;
|
||||
}
|
||||
if ((rows != 0) && (rows % rows_required_multiple != 0)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "MemoryLayout " << layout << " with a Stride of " << stride
|
||||
<< " requires that the number of rows be a multiple of "
|
||||
<< rows_required_multiple;
|
||||
}
|
||||
if ((cols != 0) && (cols % cols_required_multiple != 0)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "MemoryLayout " << layout << " with a Stride of " << stride
|
||||
<< " requires that the number of columns be a multiple of "
|
||||
<< cols_required_multiple;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (stride_required) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "MemoryLayout " << layout << " requires a Stride.";
|
||||
@@ -2561,6 +2677,23 @@ spv_result_t ValidateInt32Operand(ValidationState_t& _, const Instruction* inst,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateInt32Or64Operand(ValidationState_t& _,
|
||||
const Instruction* inst,
|
||||
uint32_t operand_index,
|
||||
const char* opcode_name,
|
||||
const char* operand_name) {
|
||||
const auto type_id =
|
||||
_.FindDef(inst->GetOperandAs<uint32_t>(operand_index))->type_id();
|
||||
if (!_.IsIntScalarType(type_id) ||
|
||||
!(_.GetBitWidth(type_id) == 32 || _.GetBitWidth(type_id) == 64)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< opcode_name << " " << operand_name << " type <id> "
|
||||
<< _.getIdName(type_id) << " is not a 32 or 64 bit integer.";
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateCooperativeVectorPointer(ValidationState_t& _,
|
||||
const Instruction* inst,
|
||||
const char* opname,
|
||||
@@ -2651,11 +2784,19 @@ spv_result_t ValidateCooperativeVectorLoadStoreNV(ValidationState_t& _,
|
||||
const auto pointer_index =
|
||||
(inst->opcode() == spv::Op::OpCooperativeVectorLoadNV) ? 2u : 0u;
|
||||
|
||||
const auto offset_index =
|
||||
(inst->opcode() == spv::Op::OpCooperativeVectorLoadNV) ? 3u : 1u;
|
||||
|
||||
if (auto error =
|
||||
ValidateCooperativeVectorPointer(_, inst, opname, pointer_index)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (auto error =
|
||||
ValidateInt32Or64Operand(_, inst, offset_index, opname, "Offset")) {
|
||||
return error;
|
||||
}
|
||||
|
||||
const auto memory_access_index =
|
||||
(inst->opcode() == spv::Op::OpCooperativeVectorLoadNV) ? 4u : 3u;
|
||||
if (inst->operands().size() > memory_access_index) {
|
||||
@@ -2705,7 +2846,8 @@ spv_result_t ValidateCooperativeVectorOuterProductNV(ValidationState_t& _,
|
||||
<< _.getIdName(b_component_type_id) << " do not match.";
|
||||
}
|
||||
|
||||
if (auto error = ValidateInt32Operand(_, inst, 1, opcode_name, "Offset")) {
|
||||
if (auto error =
|
||||
ValidateInt32Or64Operand(_, inst, 1, opcode_name, "Offset")) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2748,7 +2890,8 @@ spv_result_t ValidateCooperativeVectorReduceSumNV(ValidationState_t& _,
|
||||
<< " is not a cooperative vector type.";
|
||||
}
|
||||
|
||||
if (auto error = ValidateInt32Operand(_, inst, 1, opcode_name, "Offset")) {
|
||||
if (auto error =
|
||||
ValidateInt32Or64Operand(_, inst, 1, opcode_name, "Offset")) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2781,8 +2924,10 @@ spv_result_t ValidateCooperativeVectorMatrixMulNV(ValidationState_t& _,
|
||||
const auto input_index = 2u;
|
||||
const auto input_interpretation_index = 3u;
|
||||
const auto matrix_index = 4u;
|
||||
const auto matrix_offset_index = 5u;
|
||||
const auto matrix_interpretation_index = 6u;
|
||||
const auto bias_index = 7u;
|
||||
const auto bias_offset_index = 8u;
|
||||
const auto bias_interpretation_index = 9u;
|
||||
const auto m_index = 7u + bias_offset;
|
||||
const auto k_index = 8u + bias_offset;
|
||||
@@ -2930,15 +3075,33 @@ spv_result_t ValidateCooperativeVectorMatrixMulNV(ValidationState_t& _,
|
||||
return error;
|
||||
}
|
||||
|
||||
if (auto error = ValidateInt32Or64Operand(_, inst, matrix_offset_index,
|
||||
opcode_name, "MatrixOffset")) {
|
||||
return error;
|
||||
}
|
||||
if (has_bias) {
|
||||
if (auto error = ValidateInt32Or64Operand(_, inst, bias_offset_index,
|
||||
opcode_name, "BiasOffset")) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidatePtrComparison(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
if (_.addressing_model() == spv::AddressingModel::Logical &&
|
||||
const auto op1 = _.FindDef(inst->GetOperandAs<uint32_t>(2u));
|
||||
const auto op2 = _.FindDef(inst->GetOperandAs<uint32_t>(3u));
|
||||
const auto op1_type = _.FindDef(op1->type_id());
|
||||
const auto op2_type = _.FindDef(op2->type_id());
|
||||
spv::StorageClass sc = op1_type->GetOperandAs<spv::StorageClass>(1u);
|
||||
if ((_.addressing_model() == spv::AddressingModel::Logical ||
|
||||
_.addressing_model() == spv::AddressingModel::PhysicalStorageBuffer64) &&
|
||||
sc != spv::StorageClass::PhysicalStorageBuffer &&
|
||||
!_.features().variable_pointers) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Instruction cannot for logical addressing model be used without "
|
||||
<< "Instruction on logical pointers cannot be used without "
|
||||
"a variable pointers capability";
|
||||
}
|
||||
|
||||
@@ -2955,10 +3118,6 @@ spv_result_t ValidatePtrComparison(ValidationState_t& _,
|
||||
}
|
||||
}
|
||||
|
||||
const auto op1 = _.FindDef(inst->GetOperandAs<uint32_t>(2u));
|
||||
const auto op2 = _.FindDef(inst->GetOperandAs<uint32_t>(3u));
|
||||
const auto op1_type = _.FindDef(op1->type_id());
|
||||
const auto op2_type = _.FindDef(op2->type_id());
|
||||
if (!op1_type || (op1_type->opcode() != spv::Op::OpTypePointer &&
|
||||
op1_type->opcode() != spv::Op::OpTypeUntypedPointerKHR)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
@@ -2993,7 +3152,6 @@ spv_result_t ValidatePtrComparison(ValidationState_t& _,
|
||||
}
|
||||
}
|
||||
|
||||
spv::StorageClass sc = op1_type->GetOperandAs<spv::StorageClass>(1u);
|
||||
if (_.addressing_model() == spv::AddressingModel::Logical) {
|
||||
if (sc != spv::StorageClass::Workgroup &&
|
||||
sc != spv::StorageClass::StorageBuffer) {
|
||||
|
||||
@@ -315,9 +315,7 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
if (!ok) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
|
||||
? _.VkErrorID(10685)
|
||||
: _.VkErrorID(6426))
|
||||
<< _.VkErrorID(10685)
|
||||
<< "In the Vulkan environment, GLCompute execution model "
|
||||
"entry points require either the "
|
||||
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Validates ray tracing instructions from SPV_NV_shader_execution_reorder
|
||||
// Validates ray tracing instructions from SPV_NV_shader_invocation_reorder and
|
||||
// SPV_EXT_shader_invocation_reorder
|
||||
|
||||
#include "source/opcode.h"
|
||||
#include "source/val/instruction.h"
|
||||
@@ -37,18 +38,29 @@ uint32_t GetArrayLength(ValidationState_t& _, const Instruction* array_type) {
|
||||
return array_length;
|
||||
}
|
||||
|
||||
spv_result_t ValidateRayQueryPointer(ValidationState_t& _,
|
||||
const Instruction* inst,
|
||||
uint32_t ray_query_index) {
|
||||
const uint32_t ray_query_id = inst->GetOperandAs<uint32_t>(ray_query_index);
|
||||
auto variable = _.FindDef(ray_query_id);
|
||||
auto pointer = _.FindDef(variable->GetOperandAs<uint32_t>(0));
|
||||
if (!pointer || pointer->opcode() != spv::Op::OpTypePointer) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Query must be a pointer";
|
||||
}
|
||||
auto type = _.FindDef(pointer->GetOperandAs<uint32_t>(2));
|
||||
if (!type || type->opcode() != spv::Op::OpTypeRayQueryKHR) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Query must be a pointer to OpTypeRayQueryKHR";
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateHitObjectPointer(ValidationState_t& _,
|
||||
const Instruction* inst,
|
||||
uint32_t hit_object_index) {
|
||||
const uint32_t hit_object_id = inst->GetOperandAs<uint32_t>(hit_object_index);
|
||||
auto variable = _.FindDef(hit_object_id);
|
||||
const auto var_opcode = variable->opcode();
|
||||
if (!variable || (var_opcode != spv::Op::OpVariable &&
|
||||
var_opcode != spv::Op::OpFunctionParameter &&
|
||||
var_opcode != spv::Op::OpAccessChain)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hit Object must be a memory object declaration";
|
||||
}
|
||||
auto pointer = _.FindDef(variable->GetOperandAs<uint32_t>(0));
|
||||
if (!pointer || pointer->opcode() != spv::Op::OpTypePointer) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
@@ -62,6 +74,24 @@ spv_result_t ValidateHitObjectPointer(ValidationState_t& _,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateHitObjectPointerEXT(ValidationState_t& _,
|
||||
const Instruction* inst,
|
||||
uint32_t hit_object_index) {
|
||||
const uint32_t hit_object_id = inst->GetOperandAs<uint32_t>(hit_object_index);
|
||||
auto variable = _.FindDef(hit_object_id);
|
||||
auto pointer = _.FindDef(variable->GetOperandAs<uint32_t>(0));
|
||||
if (!pointer || pointer->opcode() != spv::Op::OpTypePointer) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hit Object must be a pointer";
|
||||
}
|
||||
auto type = _.FindDef(pointer->GetOperandAs<uint32_t>(2));
|
||||
if (!type || type->opcode() != spv::Op::OpTypeHitObjectEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Type must be OpTypeHitObjectEXT";
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateHitObjectInstructionCommonParameters(
|
||||
ValidationState_t& _, const Instruction* inst,
|
||||
uint32_t acceleration_struct_index, uint32_t instance_id_index,
|
||||
@@ -247,8 +277,10 @@ spv_result_t ValidateHitObjectInstructionCommonParameters(
|
||||
auto variable = _.FindDef(hit_object_attr_id);
|
||||
const auto var_opcode = variable->opcode();
|
||||
if (!variable || var_opcode != spv::Op::OpVariable ||
|
||||
(variable->GetOperandAs<spv::StorageClass>(2)) !=
|
||||
spv::StorageClass::HitObjectAttributeNV) {
|
||||
!((variable->GetOperandAs<spv::StorageClass>(2) ==
|
||||
spv::StorageClass::HitObjectAttributeNV) ||
|
||||
(variable->GetOperandAs<spv::StorageClass>(2) ==
|
||||
spv::StorageClass::HitObjectAttributeEXT))) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hit Object Attributes id must be a OpVariable of storage "
|
||||
"class HitObjectAttributeNV";
|
||||
@@ -728,5 +760,651 @@ spv_result_t RayReorderNVPass(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t RayReorderEXTPass(ValidationState_t& _, const Instruction* inst) {
|
||||
const spv::Op opcode = inst->opcode();
|
||||
const uint32_t result_type = inst->type_id();
|
||||
|
||||
auto RegisterOpcodeForValidModel = [](ValidationState_t& vs,
|
||||
const Instruction* rtinst) {
|
||||
std::string opcode_name = spvOpcodeString(rtinst->opcode());
|
||||
vs.function(rtinst->function()->id())
|
||||
->RegisterExecutionModelLimitation(
|
||||
[opcode_name](spv::ExecutionModel model, std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR &&
|
||||
model != spv::ExecutionModel::ClosestHitKHR &&
|
||||
model != spv::ExecutionModel::MissKHR) {
|
||||
if (message) {
|
||||
*message = opcode_name +
|
||||
" requires RayGenerationKHR, ClosestHitKHR and "
|
||||
"MissKHR execution models";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
switch (opcode) {
|
||||
case spv::Op::OpHitObjectIsMissEXT:
|
||||
case spv::Op::OpHitObjectIsHitEXT:
|
||||
case spv::Op::OpHitObjectIsEmptyEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (!_.IsBoolScalarType(result_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "expected Result Type to be bool scalar type";
|
||||
}
|
||||
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetShaderRecordBufferHandleEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
|
||||
if (!_.IsIntVectorType(result_type) ||
|
||||
(_.GetDimension(result_type) != 2) ||
|
||||
(_.GetBitWidth(result_type) != 32))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected 32-bit integer type 2-component vector as Result "
|
||||
"Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetHitKindEXT:
|
||||
case spv::Op::OpHitObjectGetPrimitiveIndexEXT:
|
||||
case spv::Op::OpHitObjectGetGeometryIndexEXT:
|
||||
case spv::Op::OpHitObjectGetInstanceIdEXT:
|
||||
case spv::Op::OpHitObjectGetInstanceCustomIndexEXT:
|
||||
case spv::Op::OpHitObjectGetShaderBindingTableRecordIndexEXT:
|
||||
case spv::Op::OpHitObjectGetRayFlagsEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
|
||||
if (!_.IsIntScalarType(result_type) || _.GetBitWidth(result_type) != 32)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected 32-bit integer type scalar as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetCurrentTimeEXT:
|
||||
case spv::Op::OpHitObjectGetRayTMaxEXT:
|
||||
case spv::Op::OpHitObjectGetRayTMinEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
|
||||
if (!_.IsFloatScalarType(result_type) || _.GetBitWidth(result_type) != 32)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected 32-bit floating-point type scalar as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetObjectToWorldEXT:
|
||||
case spv::Op::OpHitObjectGetWorldToObjectEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
|
||||
uint32_t num_rows = 0;
|
||||
uint32_t num_cols = 0;
|
||||
uint32_t col_type = 0;
|
||||
uint32_t component_type = 0;
|
||||
|
||||
if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type,
|
||||
&component_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "expected matrix type as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
}
|
||||
|
||||
if (num_cols != 4) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "expected Result Type matrix to have a Column Count of 4"
|
||||
<< spvOpcodeString(opcode);
|
||||
}
|
||||
|
||||
if (!_.IsFloatScalarType(component_type) ||
|
||||
_.GetBitWidth(result_type) != 32 || num_rows != 3) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "expected Result Type matrix to have a Column Type of "
|
||||
"3-component 32-bit float vectors: "
|
||||
<< spvOpcodeString(opcode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetObjectRayOriginEXT:
|
||||
case spv::Op::OpHitObjectGetObjectRayDirectionEXT:
|
||||
case spv::Op::OpHitObjectGetWorldRayDirectionEXT:
|
||||
case spv::Op::OpHitObjectGetWorldRayOriginEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
|
||||
if (!_.IsFloatVectorType(result_type) ||
|
||||
(_.GetDimension(result_type) != 3) ||
|
||||
(_.GetBitWidth(result_type) != 32))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected 32-bit floating-point type 3-component vector as "
|
||||
"Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetIntersectionTriangleVertexPositionsEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 2)) return error;
|
||||
|
||||
auto result_id = _.FindDef(result_type);
|
||||
if ((result_id->opcode() != spv::Op::OpTypeArray) ||
|
||||
(GetArrayLength(_, result_id) != 3) ||
|
||||
!_.IsFloatVectorType(_.GetComponentType(result_type)) ||
|
||||
_.GetDimension(_.GetComponentType(result_type)) != 3 ||
|
||||
_.GetBitWidth(_.GetComponentType(result_type)) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected 3 element array of 32-bit 3 component float "
|
||||
"vectors as Result Type: "
|
||||
<< spvOpcodeString(opcode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectGetAttributesEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
const uint32_t hit_object_attr_id = inst->GetOperandAs<uint32_t>(1);
|
||||
auto variable = _.FindDef(hit_object_attr_id);
|
||||
const auto var_opcode = variable->opcode();
|
||||
if (!variable || var_opcode != spv::Op::OpVariable ||
|
||||
variable->GetOperandAs<spv::StorageClass>(2) !=
|
||||
spv::StorageClass::HitObjectAttributeEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hit Object Attributes id must be a OpVariable of storage "
|
||||
"class HitObjectAttributeEXT";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectSetShaderBindingTableRecordIndexEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
const uint32_t sbt_index_id = _.GetOperandTypeId(inst, 1);
|
||||
if (!_.IsIntScalarType(sbt_index_id) ||
|
||||
_.GetBitWidth(sbt_index_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "SBT Index must be a 32-bit integer scalar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectExecuteShaderEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
const uint32_t payload_id = inst->GetOperandAs<uint32_t>(1);
|
||||
auto variable = _.FindDef(payload_id);
|
||||
const auto var_opcode = variable->opcode();
|
||||
if (!variable || var_opcode != spv::Op::OpVariable ||
|
||||
(variable->GetOperandAs<spv::StorageClass>(2) !=
|
||||
spv::StorageClass::RayPayloadKHR &&
|
||||
variable->GetOperandAs<spv::StorageClass>(2) !=
|
||||
spv::StorageClass::IncomingRayPayloadKHR)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Payload must be a OpVariable of storage "
|
||||
"class RayPayloadKHR or IncomingRayPayloadKHR";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectRecordEmptyEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectRecordFromQueryEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
if (auto error = ValidateRayQueryPointer(_, inst, 1)) return error;
|
||||
|
||||
if (!_.HasCapability(spv::Capability::RayQueryKHR))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< spvOpcodeString(opcode)
|
||||
<< ": requires RayQueryKHR capability";
|
||||
|
||||
// Validate SBT Record Index (operand 2)
|
||||
const uint32_t sbt_record_index_id = _.GetOperandTypeId(inst, 2);
|
||||
if (!_.IsIntScalarType(sbt_record_index_id) ||
|
||||
_.GetBitWidth(sbt_record_index_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "SBT Record Index must be a 32-bit integer scalar";
|
||||
}
|
||||
|
||||
// Validate Hit Object Attributes (operand 3)
|
||||
const uint32_t hit_object_attr_id = inst->GetOperandAs<uint32_t>(3);
|
||||
auto attr_variable = _.FindDef(hit_object_attr_id);
|
||||
const auto attr_var_opcode = attr_variable->opcode();
|
||||
if (!attr_variable || attr_var_opcode != spv::Op::OpVariable ||
|
||||
attr_variable->GetOperandAs<spv::StorageClass>(2) !=
|
||||
spv::StorageClass::HitObjectAttributeEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hit Object Attributes id must be a OpVariable of storage "
|
||||
"class HitObjectAttributeEXT";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectRecordMissEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
// Ray Flags (operand 1)
|
||||
const uint32_t ray_flags_id = _.GetOperandTypeId(inst, 1);
|
||||
if (!_.IsIntScalarType(ray_flags_id) ||
|
||||
_.GetBitWidth(ray_flags_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Flags must be a 32-bit int scalar";
|
||||
}
|
||||
|
||||
// Miss Index (operand 2)
|
||||
const uint32_t miss_index = _.GetOperandTypeId(inst, 2);
|
||||
if (!_.IsUnsignedIntScalarType(miss_index) ||
|
||||
_.GetBitWidth(miss_index) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Miss Index must be a 32-bit unsigned int scalar";
|
||||
}
|
||||
|
||||
// Ray Origin (operand 3)
|
||||
const uint32_t ray_origin = _.GetOperandTypeId(inst, 3);
|
||||
if (!_.IsFloatVectorType(ray_origin) || _.GetDimension(ray_origin) != 3 ||
|
||||
_.GetBitWidth(ray_origin) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Origin must be a 32-bit float 3-component vector";
|
||||
}
|
||||
|
||||
// Ray TMin (operand 4)
|
||||
const uint32_t ray_tmin = _.GetOperandTypeId(inst, 4);
|
||||
if (!_.IsFloatScalarType(ray_tmin) || _.GetBitWidth(ray_tmin) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray TMin must be a 32-bit float scalar";
|
||||
}
|
||||
|
||||
// Ray Direction (operand 5)
|
||||
const uint32_t ray_direction = _.GetOperandTypeId(inst, 5);
|
||||
if (!_.IsFloatVectorType(ray_direction) ||
|
||||
_.GetDimension(ray_direction) != 3 ||
|
||||
_.GetBitWidth(ray_direction) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Direction must be a 32-bit float 3-component vector";
|
||||
}
|
||||
|
||||
// Ray TMax (operand 6)
|
||||
const uint32_t ray_tmax = _.GetOperandTypeId(inst, 6);
|
||||
if (!_.IsFloatScalarType(ray_tmax) || _.GetBitWidth(ray_tmax) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray TMax must be a 32-bit float scalar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectRecordMissMotionEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
// Ray Flags (operand 1)
|
||||
const uint32_t ray_flags_id = _.GetOperandTypeId(inst, 1);
|
||||
if (!_.IsIntScalarType(ray_flags_id) ||
|
||||
_.GetBitWidth(ray_flags_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Flags must be a 32-bit int scalar";
|
||||
}
|
||||
|
||||
// Miss Index (operand 2)
|
||||
const uint32_t miss_index = _.GetOperandTypeId(inst, 2);
|
||||
if (!_.IsUnsignedIntScalarType(miss_index) ||
|
||||
_.GetBitWidth(miss_index) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Miss Index must be a 32-bit unsigned int scalar";
|
||||
}
|
||||
|
||||
// Ray Origin (operand 3)
|
||||
const uint32_t ray_origin = _.GetOperandTypeId(inst, 3);
|
||||
if (!_.IsFloatVectorType(ray_origin) || _.GetDimension(ray_origin) != 3 ||
|
||||
_.GetBitWidth(ray_origin) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Origin must be a 32-bit float 3-component vector";
|
||||
}
|
||||
|
||||
// Ray TMin (operand 4)
|
||||
const uint32_t ray_tmin = _.GetOperandTypeId(inst, 4);
|
||||
if (!_.IsFloatScalarType(ray_tmin) || _.GetBitWidth(ray_tmin) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray TMin must be a 32-bit float scalar";
|
||||
}
|
||||
|
||||
// Ray Direction (operand 5)
|
||||
const uint32_t ray_direction = _.GetOperandTypeId(inst, 5);
|
||||
if (!_.IsFloatVectorType(ray_direction) ||
|
||||
_.GetDimension(ray_direction) != 3 ||
|
||||
_.GetBitWidth(ray_direction) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray Direction must be a 32-bit float 3-component vector";
|
||||
}
|
||||
|
||||
// Ray TMax (operand 6)
|
||||
const uint32_t ray_tmax = _.GetOperandTypeId(inst, 6);
|
||||
if (!_.IsFloatScalarType(ray_tmax) || _.GetBitWidth(ray_tmax) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Ray TMax must be a 32-bit float scalar";
|
||||
}
|
||||
|
||||
// Current Time (operand 7)
|
||||
const uint32_t current_time_id = _.GetOperandTypeId(inst, 7);
|
||||
if (!_.IsFloatScalarType(current_time_id) ||
|
||||
_.GetBitWidth(current_time_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Current Time must be a 32-bit float scalar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpReorderThreadWithHintEXT: {
|
||||
std::string opcode_name = spvOpcodeString(inst->opcode());
|
||||
_.function(inst->function()->id())
|
||||
->RegisterExecutionModelLimitation(
|
||||
[opcode_name](spv::ExecutionModel model, std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR) {
|
||||
if (message) {
|
||||
*message = opcode_name +
|
||||
" requires RayGenerationKHR execution model";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const uint32_t hint_id = _.GetOperandTypeId(inst, 0);
|
||||
if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint must be a 32-bit int scalar";
|
||||
}
|
||||
|
||||
const uint32_t bits_id = _.GetOperandTypeId(inst, 1);
|
||||
if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Bits must be a 32-bit int scalar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpReorderThreadWithHitObjectEXT: {
|
||||
std::string opcode_name = spvOpcodeString(inst->opcode());
|
||||
_.function(inst->function()->id())
|
||||
->RegisterExecutionModelLimitation(
|
||||
[opcode_name](spv::ExecutionModel model, std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR) {
|
||||
if (message) {
|
||||
*message = opcode_name +
|
||||
" requires RayGenerationKHR execution model";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
if (inst->operands().size() > 1) {
|
||||
if (inst->operands().size() != 3) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint and Bits are optional together i.e "
|
||||
<< " Either both Hint and Bits should be provided or neither.";
|
||||
}
|
||||
|
||||
// Validate the optional operands Hint and Bits
|
||||
const uint32_t hint_id = _.GetOperandTypeId(inst, 1);
|
||||
if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint must be a 32-bit int scalar";
|
||||
}
|
||||
const uint32_t bits_id = _.GetOperandTypeId(inst, 2);
|
||||
if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Bits must be a 32-bit int scalar";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectTraceRayEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
if (auto error = ValidateHitObjectInstructionCommonParameters(
|
||||
_, inst, 1 /* Acceleration Struct */,
|
||||
KRayParamInvalidId /* Instance Id */,
|
||||
KRayParamInvalidId /* Primitive Id */,
|
||||
KRayParamInvalidId /* Geometry Index */, 2 /* Ray Flags */,
|
||||
3 /* Cull Mask */, KRayParamInvalidId /* Hit Kind*/,
|
||||
KRayParamInvalidId /* SBT index */, 4 /* SBT Offset */,
|
||||
5 /* SBT Stride */, KRayParamInvalidId /* SBT Record Offset */,
|
||||
KRayParamInvalidId /* SBT Record Stride */, 6 /* Miss Index */,
|
||||
7 /* Ray Origin */, 8 /* Ray TMin */, 9 /* Ray Direction */,
|
||||
10 /* Ray TMax */, 11 /* Payload */,
|
||||
KRayParamInvalidId /* Hit Object Attribute */))
|
||||
return error;
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectTraceRayMotionEXT: {
|
||||
RegisterOpcodeForValidModel(_, inst);
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
if (auto error = ValidateHitObjectInstructionCommonParameters(
|
||||
_, inst, 1 /* Acceleration Struct */,
|
||||
KRayParamInvalidId /* Instance Id */,
|
||||
KRayParamInvalidId /* Primitive Id */,
|
||||
KRayParamInvalidId /* Geometry Index */, 2 /* Ray Flags */,
|
||||
3 /* Cull Mask */, KRayParamInvalidId /* Hit Kind*/,
|
||||
KRayParamInvalidId /* SBT index */, 4 /* SBT Offset */,
|
||||
5 /* SBT Stride */, KRayParamInvalidId /* SBT Record Offset */,
|
||||
KRayParamInvalidId /* SBT Record Stride */, 6 /* Miss Index */,
|
||||
7 /* Ray Origin */, 8 /* Ray TMin */, 9 /* Ray Direction */,
|
||||
10 /* Ray TMax */, 12 /* Payload */,
|
||||
KRayParamInvalidId /* Hit Object Attribute */))
|
||||
return error;
|
||||
|
||||
// Current Time (operand 11)
|
||||
const uint32_t current_time_id = _.GetOperandTypeId(inst, 11);
|
||||
if (!_.IsFloatScalarType(current_time_id) ||
|
||||
_.GetBitWidth(current_time_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Current Time must be a 32-bit float scalar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectReorderExecuteShaderEXT: {
|
||||
std::string opcode_name = spvOpcodeString(inst->opcode());
|
||||
_.function(inst->function()->id())
|
||||
->RegisterExecutionModelLimitation(
|
||||
[opcode_name](spv::ExecutionModel model, std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR) {
|
||||
if (message) {
|
||||
*message = opcode_name +
|
||||
" requires RayGenerationKHR execution model";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
// Validate Payload (operand 1)
|
||||
const uint32_t payload_id = inst->GetOperandAs<uint32_t>(1);
|
||||
auto variable = _.FindDef(payload_id);
|
||||
const auto var_opcode = variable->opcode();
|
||||
if (!variable || var_opcode != spv::Op::OpVariable ||
|
||||
(variable->GetOperandAs<spv::StorageClass>(2) !=
|
||||
spv::StorageClass::RayPayloadKHR &&
|
||||
variable->GetOperandAs<spv::StorageClass>(2) !=
|
||||
spv::StorageClass::IncomingRayPayloadKHR)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Payload must be a OpVariable of storage "
|
||||
"class RayPayloadKHR or IncomingRayPayloadKHR";
|
||||
}
|
||||
|
||||
// Check for optional Hint and Bits (operands 2 and 3)
|
||||
if (inst->operands().size() > 2) {
|
||||
if (inst->operands().size() != 4) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint and Bits are optional together i.e "
|
||||
<< " Either both Hint and Bits should be provided or neither.";
|
||||
}
|
||||
|
||||
// Validate optional Hint and Bits
|
||||
const uint32_t hint_id = _.GetOperandTypeId(inst, 2);
|
||||
if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint must be a 32-bit int scalar";
|
||||
}
|
||||
const uint32_t bits_id = _.GetOperandTypeId(inst, 3);
|
||||
if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Bits must be a 32-bit int scalar";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectTraceReorderExecuteEXT: {
|
||||
std::string opcode_name = spvOpcodeString(inst->opcode());
|
||||
_.function(inst->function()->id())
|
||||
->RegisterExecutionModelLimitation(
|
||||
[opcode_name](spv::ExecutionModel model, std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR) {
|
||||
if (message) {
|
||||
*message = opcode_name +
|
||||
" requires RayGenerationKHR execution model";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
// Validate base trace ray parameters (operands 1-11)
|
||||
if (auto error = ValidateHitObjectInstructionCommonParameters(
|
||||
_, inst, 1 /* Acceleration Struct */,
|
||||
KRayParamInvalidId /* Instance Id */,
|
||||
KRayParamInvalidId /* Primitive Id */,
|
||||
KRayParamInvalidId /* Geometry Index */, 2 /* Ray Flags */,
|
||||
3 /* Cull Mask */, KRayParamInvalidId /* Hit Kind*/,
|
||||
KRayParamInvalidId /* SBT index */, 4 /* SBT Offset */,
|
||||
5 /* SBT Stride */, KRayParamInvalidId /* SBT Record Offset */,
|
||||
KRayParamInvalidId /* SBT Record Stride */, 6 /* Miss Index */,
|
||||
7 /* Ray Origin */, 8 /* Ray TMin */, 9 /* Ray Direction */,
|
||||
10 /* Ray TMax */, 11 /* Payload */,
|
||||
KRayParamInvalidId /* Hit Object Attribute */))
|
||||
return error;
|
||||
|
||||
// Check for optional Hint and Bits (operands 12 and 13)
|
||||
if (inst->operands().size() > 12) {
|
||||
if (inst->operands().size() != 14) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint and Bits are optional together i.e "
|
||||
<< " Either both Hint and Bits should be provided or neither.";
|
||||
}
|
||||
|
||||
// Validate optional Hint and Bits
|
||||
const uint32_t hint_id = _.GetOperandTypeId(inst, 12);
|
||||
if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint must be a 32-bit int scalar";
|
||||
}
|
||||
const uint32_t bits_id = _.GetOperandTypeId(inst, 13);
|
||||
if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Bits must be a 32-bit int scalar";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case spv::Op::OpHitObjectTraceMotionReorderExecuteEXT: {
|
||||
std::string opcode_name = spvOpcodeString(inst->opcode());
|
||||
_.function(inst->function()->id())
|
||||
->RegisterExecutionModelLimitation(
|
||||
[opcode_name](spv::ExecutionModel model, std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR) {
|
||||
if (message) {
|
||||
*message = opcode_name +
|
||||
" requires RayGenerationKHR execution model";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (auto error = ValidateHitObjectPointerEXT(_, inst, 0)) return error;
|
||||
|
||||
// Validate base trace ray parameters (operands 1-12)
|
||||
if (auto error = ValidateHitObjectInstructionCommonParameters(
|
||||
_, inst, 1 /* Acceleration Struct */,
|
||||
KRayParamInvalidId /* Instance Id */,
|
||||
KRayParamInvalidId /* Primitive Id */,
|
||||
KRayParamInvalidId /* Geometry Index */, 2 /* Ray Flags */,
|
||||
3 /* Cull Mask */, KRayParamInvalidId /* Hit Kind*/,
|
||||
KRayParamInvalidId /* SBT index */, 4 /* SBT Offset */,
|
||||
5 /* SBT Stride */, KRayParamInvalidId /* SBT Record Offset */,
|
||||
KRayParamInvalidId /* SBT Record Stride */, 6 /* Miss Index */,
|
||||
7 /* Ray Origin */, 8 /* Ray TMin */, 9 /* Ray Direction */,
|
||||
10 /* Ray TMax */, 12 /* Payload */,
|
||||
KRayParamInvalidId /* Hit Object Attribute */))
|
||||
return error;
|
||||
|
||||
// Current Time (operand 11)
|
||||
const uint32_t current_time_id = _.GetOperandTypeId(inst, 11);
|
||||
if (!_.IsFloatScalarType(current_time_id) ||
|
||||
_.GetBitWidth(current_time_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Current Time must be a 32-bit float scalar";
|
||||
}
|
||||
|
||||
// Check for optional Hint and Bits (operands 13 and 14)
|
||||
if (inst->operands().size() > 13) {
|
||||
if (inst->operands().size() != 15) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint and Bits are optional together i.e "
|
||||
<< " Either both Hint and Bits should be provided or neither.";
|
||||
}
|
||||
|
||||
// Validate optional Hint and Bits
|
||||
const uint32_t hint_id = _.GetOperandTypeId(inst, 13);
|
||||
if (!_.IsIntScalarType(hint_id) || _.GetBitWidth(hint_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Hint must be a 32-bit int scalar";
|
||||
}
|
||||
const uint32_t bits_id = _.GetOperandTypeId(inst, 14);
|
||||
if (!_.IsIntScalarType(bits_id) || _.GetBitWidth(bits_id) != 32) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Bits must be a 32-bit int scalar";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -859,6 +859,22 @@ void ValidationState_t::RegisterStorageClassConsumer(
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else if (storage_class == spv::StorageClass::HitObjectAttributeEXT) {
|
||||
function(consumer->function()->id())
|
||||
->RegisterExecutionModelLimitation([](spv::ExecutionModel model,
|
||||
std::string* message) {
|
||||
if (model != spv::ExecutionModel::RayGenerationKHR &&
|
||||
model != spv::ExecutionModel::ClosestHitKHR &&
|
||||
model != spv::ExecutionModel::MissKHR) {
|
||||
if (message) {
|
||||
*message =
|
||||
"HitObjectAttributeEXT Storage Class is limited to "
|
||||
"RayGenerationKHR, ClosestHitKHR or MissKHR execution model";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2032,6 +2048,7 @@ bool ValidationState_t::IsValidStorageClass(
|
||||
case spv::StorageClass::ShaderRecordBufferKHR:
|
||||
case spv::StorageClass::TaskPayloadWorkgroupEXT:
|
||||
case spv::StorageClass::HitObjectAttributeNV:
|
||||
case spv::StorageClass::HitObjectAttributeEXT:
|
||||
case spv::StorageClass::TileImageEXT:
|
||||
case spv::StorageClass::NodePayloadAMDX:
|
||||
case spv::StorageClass::TileAttachmentQCOM:
|
||||
@@ -2254,6 +2271,12 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
|
||||
return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282);
|
||||
case 4283:
|
||||
return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283);
|
||||
case 4284:
|
||||
return VUID_WRAP(VUID-LocalInvocationIndex-LocalInvocationIndex-04284);
|
||||
case 4285:
|
||||
return VUID_WRAP(VUID-LocalInvocationIndex-LocalInvocationIndex-04285);
|
||||
case 4286:
|
||||
return VUID_WRAP(VUID-LocalInvocationIndex-LocalInvocationIndex-04286);
|
||||
case 4293:
|
||||
return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293);
|
||||
case 4294:
|
||||
@@ -2538,8 +2561,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-OpTypeRuntimeArray-04680);
|
||||
case 4682:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682);
|
||||
case 6426:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-06426); // formally 04683
|
||||
case 4685:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
|
||||
case 4686:
|
||||
@@ -2752,7 +2773,7 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
|
||||
case 10684:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-None-10684);
|
||||
case 10685:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-None-10685);
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-None-10685); // formally 04683/06426
|
||||
case 10824:
|
||||
// This use to be a standalone, but maintenance9 will set allow_vulkan_32_bit_bitwise now
|
||||
return VUID_WRAP(VUID-RuntimeSpirv-None-10824);
|
||||
@@ -2790,6 +2811,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-TessLevelInner-10880);
|
||||
case 11167:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-OpUntypedVariableKHR-11167);
|
||||
case 11805:
|
||||
return VUID_WRAP(VUID-StandaloneSpirv-OpArrayLength-11805);
|
||||
default:
|
||||
return ""; // unknown id
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user