Updated spirv-tools.

This commit is contained in:
Бранимир Караџић 2024-02-09 22:20:51 -08:00
parent 56f7af3103
commit 3ac2dda244
39 changed files with 1094 additions and 72 deletions

View File

@ -1,4 +1,4 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017-2024 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and/or associated documentation files (the "Materials"),

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018-2024 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and/or associated documentation files (the "Materials"),

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018-2024 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and/or associated documentation files (the "Materials"),

View File

@ -1 +1 @@
"v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-7-g57aba7ff"
"v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-37-g58b2f0b6"

View File

@ -44,6 +44,7 @@ static const spv::Capability pygen_variable_caps_Kernel[] = {spv::Capability::Ke
static const spv::Capability pygen_variable_caps_KernelImageQuery[] = {spv::Capability::Kernel, spv::Capability::ImageQuery};
static const spv::Capability pygen_variable_caps_LiteralSampler[] = {spv::Capability::LiteralSampler};
static const spv::Capability pygen_variable_caps_LongCompositesINTEL[] = {spv::Capability::LongCompositesINTEL};
static const spv::Capability pygen_variable_caps_MaskedGatherScatterINTEL[] = {spv::Capability::MaskedGatherScatterINTEL};
static const spv::Capability pygen_variable_caps_Matrix[] = {spv::Capability::Matrix};
static const spv::Capability pygen_variable_caps_MemoryAccessAliasingINTEL[] = {spv::Capability::MemoryAccessAliasingINTEL};
static const spv::Capability pygen_variable_caps_MeshShadingEXT[] = {spv::Capability::MeshShadingEXT};
@ -51,6 +52,7 @@ static const spv::Capability pygen_variable_caps_MeshShadingNV[] = {spv::Capabil
static const spv::Capability pygen_variable_caps_NamedBarrier[] = {spv::Capability::NamedBarrier};
static const spv::Capability pygen_variable_caps_PipeStorage[] = {spv::Capability::PipeStorage};
static const spv::Capability pygen_variable_caps_Pipes[] = {spv::Capability::Pipes};
static const spv::Capability pygen_variable_caps_QuadControlKHR[] = {spv::Capability::QuadControlKHR};
static const spv::Capability pygen_variable_caps_RayQueryKHR[] = {spv::Capability::RayQueryKHR};
static const spv::Capability pygen_variable_caps_RayQueryPositionFetchKHR[] = {spv::Capability::RayQueryPositionFetchKHR};
static const spv::Capability pygen_variable_caps_RayTracingKHR[] = {spv::Capability::RayTracingKHR};
@ -520,6 +522,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
{"FinalizeNodePayloadsAMDX", spv::Op::OpFinalizeNodePayloadsAMDX, 1, pygen_variable_caps_ShaderEnqueueAMDX, 1, {SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"FinishWritingNodePayloadAMDX", spv::Op::OpFinishWritingNodePayloadAMDX, 1, pygen_variable_caps_ShaderEnqueueAMDX, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"InitializeNodePayloadsAMDX", spv::Op::OpInitializeNodePayloadsAMDX, 1, pygen_variable_caps_ShaderEnqueueAMDX, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"GroupNonUniformQuadAllKHR", spv::Op::OpGroupNonUniformQuadAllKHR, 1, pygen_variable_caps_QuadControlKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"GroupNonUniformQuadAnyKHR", spv::Op::OpGroupNonUniformQuadAnyKHR, 1, pygen_variable_caps_QuadControlKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"HitObjectRecordHitMotionNV", spv::Op::OpHitObjectRecordHitMotionNV, 2, pygen_variable_caps_ShaderInvocationReorderNVRayTracingMotionBlurNV, 14, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"HitObjectRecordHitWithIndexMotionNV", spv::Op::OpHitObjectRecordHitWithIndexMotionNV, 2, pygen_variable_caps_ShaderInvocationReorderNVRayTracingMotionBlurNV, 13, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"HitObjectRecordMissMotionNV", spv::Op::OpHitObjectRecordMissMotionNV, 2, pygen_variable_caps_ShaderInvocationReorderNVRayTracingMotionBlurNV, 7, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
@ -841,5 +845,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
{"GroupBitwiseXorKHR", spv::Op::OpGroupBitwiseXorKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"GroupLogicalAndKHR", spv::Op::OpGroupLogicalAndKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"GroupLogicalOrKHR", spv::Op::OpGroupLogicalOrKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"GroupLogicalXorKHR", spv::Op::OpGroupLogicalXorKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}
{"GroupLogicalXorKHR", spv::Op::OpGroupLogicalXorKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"MaskedGatherINTEL", spv::Op::OpMaskedGatherINTEL, 1, pygen_variable_caps_MaskedGatherScatterINTEL, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"MaskedScatterINTEL", spv::Op::OpMaskedScatterINTEL, 1, pygen_variable_caps_MaskedGatherScatterINTEL, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}
};

File diff suppressed because one or more lines are too long

View File

@ -58,6 +58,7 @@ kSPV_INTEL_io_pipes,
kSPV_INTEL_kernel_attributes,
kSPV_INTEL_long_composites,
kSPV_INTEL_loop_fuse,
kSPV_INTEL_masked_gather_scatter,
kSPV_INTEL_media_block_io,
kSPV_INTEL_memory_access_aliasing,
kSPV_INTEL_optnone,
@ -76,15 +77,18 @@ kSPV_KHR_cooperative_matrix,
kSPV_KHR_device_group,
kSPV_KHR_expect_assume,
kSPV_KHR_float_controls,
kSPV_KHR_float_controls2,
kSPV_KHR_fragment_shader_barycentric,
kSPV_KHR_fragment_shading_rate,
kSPV_KHR_integer_dot_product,
kSPV_KHR_linkonce_odr,
kSPV_KHR_maximal_reconvergence,
kSPV_KHR_multiview,
kSPV_KHR_no_integer_wrap_decoration,
kSPV_KHR_non_semantic_info,
kSPV_KHR_physical_storage_buffer,
kSPV_KHR_post_depth_coverage,
kSPV_KHR_quad_control,
kSPV_KHR_ray_cull_mask,
kSPV_KHR_ray_query,
kSPV_KHR_ray_tracing,

View File

@ -38,4 +38,5 @@
{37, "heroseh", "Hero C Compiler", "heroseh Hero C Compiler"},
{38, "Meta", "SparkSL", "Meta SparkSL"},
{39, "SirLynix", "Nazara ShaderLang Compiler", "SirLynix Nazara ShaderLang Compiler"},
{40, "NVIDIA", "Slang Compiler", "NVIDIA Slang Compiler"},
{40, "NVIDIA", "Slang Compiler", "NVIDIA Slang Compiler"},
{41, "Zig Software Foundation", "Zig Compiler", "Zig Software Foundation Zig Compiler"},

View File

@ -15,7 +15,6 @@ static const spv::Capability pygen_variable_caps_DeviceEnqueue[] = {spv::Capabil
static const spv::Capability pygen_variable_caps_DeviceGroup[] = {spv::Capability::DeviceGroup};
static const spv::Capability pygen_variable_caps_DrawParameters[] = {spv::Capability::DrawParameters};
static const spv::Capability pygen_variable_caps_DrawParametersMeshShadingNVMeshShadingEXT[] = {spv::Capability::DrawParameters, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_FPFastMathModeINTEL[] = {spv::Capability::FPFastMathModeINTEL};
static const spv::Capability pygen_variable_caps_FPGAArgumentInterfacesINTEL[] = {spv::Capability::FPGAArgumentInterfacesINTEL};
static const spv::Capability pygen_variable_caps_FPGABufferLocationINTEL[] = {spv::Capability::FPGABufferLocationINTEL};
static const spv::Capability pygen_variable_caps_FPGAClusterAttributesINTEL[] = {spv::Capability::FPGAClusterAttributesINTEL};
@ -29,6 +28,8 @@ static const spv::Capability pygen_variable_caps_FPGALoopControlsINTEL[] = {spv:
static const spv::Capability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {spv::Capability::FPGAMemoryAccessesINTEL};
static const spv::Capability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {spv::Capability::FPGAMemoryAttributesINTEL};
static const spv::Capability pygen_variable_caps_FPMaxErrorINTEL[] = {spv::Capability::FPMaxErrorINTEL};
static const spv::Capability pygen_variable_caps_FloatControls2[] = {spv::Capability::FloatControls2};
static const spv::Capability pygen_variable_caps_FloatControls2FPFastMathModeINTEL[] = {spv::Capability::FloatControls2, spv::Capability::FPFastMathModeINTEL};
static const spv::Capability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {spv::Capability::FragmentBarycentricNV, spv::Capability::FragmentBarycentricKHR};
static const spv::Capability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {spv::Capability::FragmentDensityEXT, spv::Capability::ShadingRateNV};
static const spv::Capability pygen_variable_caps_FragmentFullyCoveredEXT[] = {spv::Capability::FragmentFullyCoveredEXT};
@ -64,6 +65,7 @@ static const spv::Capability pygen_variable_caps_Int64[] = {spv::Capability::Int
static const spv::Capability pygen_variable_caps_Int64ImageEXT[] = {spv::Capability::Int64ImageEXT};
static const spv::Capability pygen_variable_caps_Int8[] = {spv::Capability::Int8};
static const spv::Capability pygen_variable_caps_Kernel[] = {spv::Capability::Kernel};
static const spv::Capability pygen_variable_caps_KernelFloatControls2[] = {spv::Capability::Kernel, spv::Capability::FloatControls2};
static const spv::Capability pygen_variable_caps_KernelGroupNonUniform[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniform};
static const spv::Capability pygen_variable_caps_KernelGroupNonUniformSubgroupBallotKHR[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniform, spv::Capability::SubgroupBallotKHR};
static const spv::Capability pygen_variable_caps_KernelGroupNonUniformArithmeticGroupNonUniformBallot[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniformArithmetic, spv::Capability::GroupNonUniformBallot};
@ -83,6 +85,7 @@ static const spv::Capability pygen_variable_caps_OptNoneINTEL[] = {spv::Capabili
static const spv::Capability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {spv::Capability::PerViewAttributesNV, spv::Capability::MeshShadingNV};
static const spv::Capability pygen_variable_caps_PhysicalStorageBufferAddresses[] = {spv::Capability::PhysicalStorageBufferAddresses};
static const spv::Capability pygen_variable_caps_Pipes[] = {spv::Capability::Pipes};
static const spv::Capability pygen_variable_caps_QuadControlKHR[] = {spv::Capability::QuadControlKHR};
static const spv::Capability pygen_variable_caps_RayCullMaskKHR[] = {spv::Capability::RayCullMaskKHR};
static const spv::Capability pygen_variable_caps_RayQueryKHR[] = {spv::Capability::RayQueryKHR};
static const spv::Capability pygen_variable_caps_RayQueryKHRRayTracingKHR[] = {spv::Capability::RayQueryKHR, spv::Capability::RayTracingKHR};
@ -196,6 +199,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_io_pipes[] = {spv
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_kernel_attributes[] = {spvtools::Extension::kSPV_INTEL_kernel_attributes};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_long_composites[] = {spvtools::Extension::kSPV_INTEL_long_composites};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_loop_fuse[] = {spvtools::Extension::kSPV_INTEL_loop_fuse};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_masked_gather_scatter[] = {spvtools::Extension::kSPV_INTEL_masked_gather_scatter};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_media_block_io[] = {spvtools::Extension::kSPV_INTEL_media_block_io};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_memory_access_aliasing[] = {spvtools::Extension::kSPV_INTEL_memory_access_aliasing};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_optnone[] = {spvtools::Extension::kSPV_INTEL_optnone};
@ -214,13 +218,16 @@ static const spvtools::Extension pygen_variable_exts_SPV_KHR_cooperative_matrix[
static const spvtools::Extension pygen_variable_exts_SPV_KHR_device_group[] = {spvtools::Extension::kSPV_KHR_device_group};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_expect_assume[] = {spvtools::Extension::kSPV_KHR_expect_assume};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_float_controls[] = {spvtools::Extension::kSPV_KHR_float_controls};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_float_controls2[] = {spvtools::Extension::kSPV_KHR_float_controls2};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_fragment_shader_barycentricSPV_NV_fragment_shader_barycentric[] = {spvtools::Extension::kSPV_KHR_fragment_shader_barycentric, spvtools::Extension::kSPV_NV_fragment_shader_barycentric};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_fragment_shading_rate[] = {spvtools::Extension::kSPV_KHR_fragment_shading_rate};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_integer_dot_product[] = {spvtools::Extension::kSPV_KHR_integer_dot_product};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_linkonce_odr[] = {spvtools::Extension::kSPV_KHR_linkonce_odr};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_maximal_reconvergence[] = {spvtools::Extension::kSPV_KHR_maximal_reconvergence};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_multiview[] = {spvtools::Extension::kSPV_KHR_multiview};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_no_integer_wrap_decoration[] = {spvtools::Extension::kSPV_KHR_no_integer_wrap_decoration};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_post_depth_coverage[] = {spvtools::Extension::kSPV_KHR_post_depth_coverage};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_quad_control[] = {spvtools::Extension::kSPV_KHR_quad_control};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_ray_cull_mask[] = {spvtools::Extension::kSPV_KHR_ray_cull_mask};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_ray_query[] = {spvtools::Extension::kSPV_KHR_ray_query};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_ray_querySPV_KHR_ray_tracing[] = {spvtools::Extension::kSPV_KHR_ray_query, spvtools::Extension::kSPV_KHR_ray_tracing};
@ -290,8 +297,11 @@ static const spv_operand_desc_t pygen_variable_FPFastMathModeEntries[] = {
{"NSZ", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"AllowRecip", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"Fast", 0x0010, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"AllowContractFastINTEL", 0x10000, 1, pygen_variable_caps_FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"AllowReassocINTEL", 0x20000, 1, pygen_variable_caps_FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
{"AllowContract", 0x10000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"AllowContractFastINTEL", 0x10000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"AllowReassoc", 0x20000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"AllowReassocINTEL", 0x20000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"AllowTransform", 0x40000, 1, pygen_variable_caps_FloatControls2, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_SelectionControlEntries[] = {
@ -408,7 +418,8 @@ static const spv_operand_desc_t pygen_variable_SourceLanguageEntries[] = {
{"HERO_C", 8, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"NZSL", 9, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"WGSL", 10, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"Slang", 11, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}
{"Slang", 11, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"Zig", 12, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_ExecutionModelEntries[] = {
@ -515,6 +526,8 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = {
{"StencilRefUnchangedBackAMD", 5082, 1, pygen_variable_caps_StencilExportEXT, 2, pygen_variable_exts_SPV_AMD_shader_early_and_late_fragment_testsSPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
{"StencilRefGreaterBackAMD", 5083, 1, pygen_variable_caps_StencilExportEXT, 2, pygen_variable_exts_SPV_AMD_shader_early_and_late_fragment_testsSPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
{"StencilRefLessBackAMD", 5084, 1, pygen_variable_caps_StencilExportEXT, 2, pygen_variable_exts_SPV_AMD_shader_early_and_late_fragment_testsSPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
{"QuadDerivativesKHR", 5088, 1, pygen_variable_caps_QuadControlKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"RequireFullQuadsKHR", 5089, 1, pygen_variable_caps_QuadControlKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"OutputLinesNV", 5269, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu},
{"OutputLinesEXT", 5269, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu},
{"OutputPrimitivesNV", 5270, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
@ -539,6 +552,8 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = {
{"NoGlobalOffsetINTEL", 5895, 1, pygen_variable_caps_KernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {}, 0xffffffffu, 0xffffffffu},
{"NumSIMDWorkitemsINTEL", 5896, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"SchedulerTargetFmaxMhzINTEL", 5903, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaximallyReconvergesKHR", 6023, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_maximal_reconvergence, {}, 0xffffffffu, 0xffffffffu},
{"FPFastMathDefault", 6028, 1, pygen_variable_caps_FloatControls2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu},
{"StreamingInterfaceINTEL", 6154, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"RegisterMapInterfaceINTEL", 6160, 1, pygen_variable_caps_FPGAKernelAttributesv2INTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"NamedBarrierCountINTEL", 6417, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}
@ -802,7 +817,7 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
{"XfbStride", 37, 1, pygen_variable_caps_TransformFeedback, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"FuncParamAttr", 38, 1, pygen_variable_caps_Kernel, 0, nullptr, {SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"FPRoundingMode", 39, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_FP_ROUNDING_MODE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"FPFastMathMode", 40, 1, pygen_variable_caps_Kernel, 0, nullptr, {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"FPFastMathMode", 40, 2, pygen_variable_caps_KernelFloatControls2, 0, nullptr, {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"LinkageAttributes", 41, 1, pygen_variable_caps_Linkage, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_STRING, SPV_OPERAND_TYPE_LINKAGE_TYPE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"NoContraction", 42, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
{"InputAttachmentIndex", 43, 1, pygen_variable_caps_InputAttachment, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
@ -1194,6 +1209,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"Int64ImageEXT", 5016, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_image_int64, {}, 0xffffffffu, 0xffffffffu},
{"ShaderClockKHR", 5055, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_shader_clock, {}, 0xffffffffu, 0xffffffffu},
{"ShaderEnqueueAMDX", 5067, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_AMDX_shader_enqueue, {}, 0xffffffffu, 0xffffffffu},
{"QuadControlKHR", 5087, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_quad_control, {}, 0xffffffffu, 0xffffffffu},
{"SampleMaskOverrideCoverageNV", 5249, 1, pygen_variable_caps_SampleRateShading, 1, pygen_variable_exts_SPV_NV_sample_mask_override_coverage, {}, 0xffffffffu, 0xffffffffu},
{"GeometryShaderPassthroughNV", 5251, 1, pygen_variable_caps_Geometry, 1, pygen_variable_exts_SPV_NV_geometry_shader_passthrough, {}, 0xffffffffu, 0xffffffffu},
{"ShaderViewportIndexLayerEXT", 5254, 1, pygen_variable_caps_MultiViewport, 2, pygen_variable_exts_SPV_EXT_shader_viewport_index_layerSPV_NV_viewport_array2, {}, 0xffffffffu, 0xffffffffu},
@ -1313,6 +1329,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"CooperativeMatrixKHR", 6022, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_cooperative_matrix, {}, 0xffffffffu, 0xffffffffu},
{"BitInstructions", 6025, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_bit_instructions, {}, 0xffffffffu, 0xffffffffu},
{"GroupNonUniformRotateKHR", 6026, 1, pygen_variable_caps_GroupNonUniform, 1, pygen_variable_exts_SPV_KHR_subgroup_rotate, {}, 0xffffffffu, 0xffffffffu},
{"FloatControls2", 6029, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_float_controls2, {}, 0xffffffffu, 0xffffffffu},
{"AtomicFloat32AddEXT", 6033, 0, nullptr, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, {}, 0xffffffffu, 0xffffffffu},
{"AtomicFloat64AddEXT", 6034, 0, nullptr, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, {}, 0xffffffffu, 0xffffffffu},
{"LongCompositesINTEL", 6089, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_long_composites, {}, 0xffffffffu, 0xffffffffu},
@ -1329,6 +1346,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"GlobalVariableHostAccessINTEL", 6187, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_global_variable_host_access, {}, 0xffffffffu, 0xffffffffu},
{"GlobalVariableFPGADecorationsINTEL", 6189, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_global_variable_fpga_decorations, {}, 0xffffffffu, 0xffffffffu},
{"GroupUniformArithmeticKHR", 6400, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_uniform_group_instructions, {}, 0xffffffffu, 0xffffffffu},
{"MaskedGatherScatterINTEL", 6427, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_masked_gather_scatter, {}, 0xffffffffu, 0xffffffffu},
{"CacheControlsINTEL", 6441, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_cache_controls, {}, 0xffffffffu, 0xffffffffu}
};

View File

@ -1003,6 +1003,10 @@ Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t ds_from,
// OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that
// order.
Optimizer::PassToken CreateInvocationInterlockPlacementPass();
// Creates a pass to add/remove maximal reconvergence execution mode.
// This pass either adds or removes maximal reconvergence from all entry points.
Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add);
} // namespace spvtools
#endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_

View File

@ -534,6 +534,8 @@ bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
case spv::Op::OpGroupNonUniformQuadBroadcast:
case spv::Op::OpGroupNonUniformQuadSwap:
case spv::Op::OpGroupNonUniformRotateKHR:
case spv::Op::OpGroupNonUniformQuadAllKHR:
case spv::Op::OpGroupNonUniformQuadAnyKHR:
return true;
default:
return false;

View File

@ -985,6 +985,7 @@ void AggressiveDCEPass::InitExtensions() {
"SPV_NV_shader_image_footprint",
"SPV_NV_shading_rate",
"SPV_NV_mesh_shader",
"SPV_EXT_mesh_shader",
"SPV_NV_ray_tracing",
"SPV_KHR_ray_tracing",
"SPV_KHR_ray_query",

View File

@ -98,6 +98,17 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
return false;
}
// Note: This means that the instructions in a break block will execute as if
// they were still diverged according to the loop iteration. This restricts
// potential transformations an implementation may perform on the IR to match
// shader author expectations. Similarly, instructions in the loop construct
// cannot be moved into the continue construct unless it can be proven that
// invocations are always converged.
if (succ_is_merge && context->get_feature_mgr()->HasExtension(
kSPV_KHR_maximal_reconvergence)) {
return false;
}
if (pred_is_merge && IsContinue(context, lab_id)) {
// Cannot merge a continue target with a merge block.
return false;

View File

@ -21,6 +21,59 @@ namespace opt {
namespace {
constexpr uint32_t kExtractCompositeIdInIdx = 0;
// Returns the value obtained by extracting the |number_of_bits| least
// significant bits from |value|, and sign-extending it to 64-bits.
uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) {
if (number_of_bits == 64) return value;
uint64_t mask_for_sign_bit = 1ull << (number_of_bits - 1);
uint64_t mask_for_significant_bits = (mask_for_sign_bit << 1) - 1ull;
if (value & mask_for_sign_bit) {
// Set upper bits to 1
value |= ~mask_for_significant_bits;
} else {
// Clear the upper bits
value &= mask_for_significant_bits;
}
return value;
}
// Returns the value obtained by extracting the |number_of_bits| least
// significant bits from |value|, and zero-extending it to 64-bits.
uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) {
if (number_of_bits == 64) return value;
uint64_t mask_for_first_bit_to_clear = 1ull << (number_of_bits);
uint64_t mask_for_bits_to_keep = mask_for_first_bit_to_clear - 1;
value &= mask_for_bits_to_keep;
return value;
}
// Returns a constant whose value is `value` and type is `type`. This constant
// will be generated by `const_mgr`. The type must be a scalar integer type.
const analysis::Constant* GenerateIntegerConstant(
const analysis::Integer* integer_type, uint64_t result,
analysis::ConstantManager* const_mgr) {
assert(integer_type != nullptr);
std::vector<uint32_t> words;
if (integer_type->width() == 64) {
// In the 64-bit case, two words are needed to represent the value.
words = {static_cast<uint32_t>(result),
static_cast<uint32_t>(result >> 32)};
} else {
// In all other cases, only a single word is needed.
assert(integer_type->width() <= 32);
if (integer_type->IsSigned()) {
result = SignExtendValue(result, integer_type->width());
} else {
result = ZeroExtendValue(result, integer_type->width());
}
words = {static_cast<uint32_t>(result)};
}
return const_mgr->GetConstant(integer_type, words);
}
// Returns a constants with the value NaN of the given type. Only works for
// 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs.
const analysis::Constant* GetNan(const analysis::Type* type,
@ -676,7 +729,6 @@ ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) {
return [scalar_rule](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
@ -716,6 +768,64 @@ ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) {
};
}
// Returns a |ConstantFoldingRule| that folds binary scalar ops
// using |scalar_rule| and binary vectors ops by applying
// |scalar_rule| to the elements of the vector. The folding rule assumes that op
// has two inputs. For regular instruction, those are in operands 0 and 1. For
// extended instruction, they are in operands 1 and 2. If an element in
// |constants| is not nullprt, then the constant's type is |Float|, |Integer|,
// or |Vector| whose element type is |Float| or |Integer|.
ConstantFoldingRule FoldBinaryOp(BinaryScalarFoldingRule scalar_rule) {
return [scalar_rule](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(constants.size() == inst->NumInOperands());
assert(constants.size() == (inst->opcode() == spv::Op::OpExtInst ? 3 : 2));
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
const analysis::Vector* vector_type = result_type->AsVector();
const analysis::Constant* arg1 =
(inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0];
const analysis::Constant* arg2 =
(inst->opcode() == spv::Op::OpExtInst) ? constants[2] : constants[1];
if (arg1 == nullptr || arg2 == nullptr) {
return nullptr;
}
if (vector_type == nullptr) {
return scalar_rule(result_type, arg1, arg2, const_mgr);
}
std::vector<const analysis::Constant*> a_components;
std::vector<const analysis::Constant*> b_components;
std::vector<const analysis::Constant*> results_components;
a_components = arg1->GetVectorComponents(const_mgr);
b_components = arg2->GetVectorComponents(const_mgr);
assert(a_components.size() == b_components.size());
// Fold each component of the vector.
for (uint32_t i = 0; i < a_components.size(); ++i) {
results_components.push_back(scalar_rule(vector_type->element_type(),
a_components[i], b_components[i],
const_mgr));
if (results_components[i] == nullptr) {
return nullptr;
}
}
// Build the constant object and return it.
std::vector<uint32_t> ids;
for (const analysis::Constant* member : results_components) {
ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id());
}
return const_mgr->GetConstant(vector_type, ids);
};
}
// Returns a |ConstantFoldingRule| that folds unary floating point scalar ops
// using |scalar_rule| and unary float point vectors ops by applying
// |scalar_rule| to the elements of the vector. The |ConstantFoldingRule|
@ -1587,6 +1697,72 @@ BinaryScalarFoldingRule FoldFTranscendentalBinary(double (*fp)(double,
return nullptr;
};
}
enum Sign { Signed, Unsigned };
// Returns a BinaryScalarFoldingRule that applies `op` to the scalars.
// The `signedness` is used to determine if the operands should be interpreted
// as signed or unsigned. If the operands are signed, the value will be sign
// extended before the value is passed to `op`. Otherwise the values will be
// zero extended.
template <Sign signedness>
BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t,
uint64_t)) {
return
[op](const analysis::Type* result_type, const analysis::Constant* a,
const analysis::Constant* b,
analysis::ConstantManager* const_mgr) -> const analysis::Constant* {
assert(result_type != nullptr && a != nullptr && b != nullptr);
const analysis::Integer* integer_type = result_type->AsInteger();
assert(integer_type != nullptr);
assert(integer_type == a->type()->AsInteger());
assert(integer_type == b->type()->AsInteger());
// In SPIR-V, all operations support unsigned types, but the way they
// are interpreted depends on the opcode. This is why we use the
// template argument to determine how to interpret the operands.
uint64_t ia = (signedness == Signed ? a->GetSignExtendedValue()
: a->GetZeroExtendedValue());
uint64_t ib = (signedness == Signed ? b->GetSignExtendedValue()
: b->GetZeroExtendedValue());
uint64_t result = op(ia, ib);
const analysis::Constant* result_constant =
GenerateIntegerConstant(integer_type, result, const_mgr);
return result_constant;
};
}
// A scalar folding rule that folds OpSConvert.
const analysis::Constant* FoldScalarSConvert(
const analysis::Type* result_type, const analysis::Constant* a,
analysis::ConstantManager* const_mgr) {
assert(result_type != nullptr);
assert(a != nullptr);
assert(const_mgr != nullptr);
const analysis::Integer* integer_type = result_type->AsInteger();
assert(integer_type && "The result type of an SConvert");
int64_t value = a->GetSignExtendedValue();
return GenerateIntegerConstant(integer_type, value, const_mgr);
}
// A scalar folding rule that folds OpUConvert.
const analysis::Constant* FoldScalarUConvert(
const analysis::Type* result_type, const analysis::Constant* a,
analysis::ConstantManager* const_mgr) {
assert(result_type != nullptr);
assert(a != nullptr);
assert(const_mgr != nullptr);
const analysis::Integer* integer_type = result_type->AsInteger();
assert(integer_type && "The result type of an UConvert");
uint64_t value = a->GetZeroExtendedValue();
// If the operand was an unsigned value with less than 32-bit, it would have
// been sign extended earlier, and we need to clear those bits.
auto* operand_type = a->type()->AsInteger();
value = ZeroExtendValue(value, operand_type->width());
return GenerateIntegerConstant(integer_type, value, const_mgr);
}
} // namespace
void ConstantFoldingRules::AddFoldingRules() {
@ -1604,6 +1780,8 @@ void ConstantFoldingRules::AddFoldingRules() {
rules_[spv::Op::OpConvertFToU].push_back(FoldFToI());
rules_[spv::Op::OpConvertSToF].push_back(FoldIToF());
rules_[spv::Op::OpConvertUToF].push_back(FoldIToF());
rules_[spv::Op::OpSConvert].push_back(FoldUnaryOp(FoldScalarSConvert));
rules_[spv::Op::OpUConvert].push_back(FoldUnaryOp(FoldScalarUConvert));
rules_[spv::Op::OpDot].push_back(FoldOpDotWithConstants());
rules_[spv::Op::OpFAdd].push_back(FoldFAdd());
@ -1662,6 +1840,46 @@ void ConstantFoldingRules::AddFoldingRules() {
rules_[spv::Op::OpSNegate].push_back(FoldSNegate());
rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16());
rules_[spv::Op::OpIAdd].push_back(
FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
[](uint64_t a, uint64_t b) { return a + b; })));
rules_[spv::Op::OpISub].push_back(
FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
[](uint64_t a, uint64_t b) { return a - b; })));
rules_[spv::Op::OpIMul].push_back(
FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
[](uint64_t a, uint64_t b) { return a * b; })));
rules_[spv::Op::OpUDiv].push_back(
FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
[](uint64_t a, uint64_t b) { return (b != 0 ? a / b : 0); })));
rules_[spv::Op::OpSDiv].push_back(FoldBinaryOp(
FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
return (b != 0 ? static_cast<uint64_t>(static_cast<int64_t>(a) /
static_cast<int64_t>(b))
: 0);
})));
rules_[spv::Op::OpUMod].push_back(
FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
[](uint64_t a, uint64_t b) { return (b != 0 ? a % b : 0); })));
rules_[spv::Op::OpSRem].push_back(FoldBinaryOp(
FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
return (b != 0 ? static_cast<uint64_t>(static_cast<int64_t>(a) %
static_cast<int64_t>(b))
: 0);
})));
rules_[spv::Op::OpSMod].push_back(FoldBinaryOp(
FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
if (b == 0) return static_cast<uint64_t>(0ull);
int64_t signed_a = static_cast<int64_t>(a);
int64_t signed_b = static_cast<int64_t>(b);
int64_t result = signed_a % signed_b;
if ((signed_b < 0) != (result < 0)) result += signed_b;
return static_cast<uint64_t>(result);
})));
// Add rules for GLSLstd450
FeatureManager* feature_manager = context_->get_feature_mgr();
uint32_t ext_inst_glslstd450_id =

View File

@ -171,6 +171,19 @@ bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
bool ConvertToHalfPass::GenHalfArith(Instruction* inst) {
bool modified = false;
// If this is a OpCompositeExtract instruction and has a struct operand, we
// should not relax this instruction. Doing so could cause a mismatch between
// the result type and the struct member type.
bool hasStructOperand = false;
if (inst->opcode() == spv::Op::OpCompositeExtract) {
inst->ForEachInId([&hasStructOperand, this](uint32_t* idp) {
Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
if (IsStruct(op_inst)) hasStructOperand = true;
});
if (hasStructOperand) {
return false;
}
}
// Convert all float32 based operands to float16 equivalent and change
// instruction type to float16 equivalent.
inst->ForEachInId([&inst, &modified, this](uint32_t* idp) {
@ -303,12 +316,19 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) {
if (closure_ops_.count(inst->opcode()) == 0) return false;
// Can relax if all float operands are relaxed
bool relax = true;
inst->ForEachInId([&relax, this](uint32_t* idp) {
bool hasStructOperand = false;
inst->ForEachInId([&relax, &hasStructOperand, this](uint32_t* idp) {
Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
if (IsStruct(op_inst)) relax = false;
if (IsStruct(op_inst)) hasStructOperand = true;
if (!IsFloat(op_inst, 32)) return;
if (!IsRelaxed(*idp)) relax = false;
});
// If the instruction has a struct operand, we should not relax it, even if
// all its uses are relaxed. Doing so could cause a mismatch between the
// result type and the struct member type.
if (hasStructOperand) {
return false;
}
if (relax) {
AddRelaxed(inst->result_id());
return true;

View File

@ -27,28 +27,6 @@ namespace spvtools {
namespace opt {
namespace analysis {
// Class for representing a use of id. Note that:
// * Result type id is a use.
// * Ids referenced in OpSectionMerge & OpLoopMerge are considered as use.
// * Ids referenced in OpPhi's in operands are considered as use.
struct Use {
Instruction* inst; // Instruction using the id.
uint32_t operand_index; // logical operand index of the id use. This can be
// the index of result type id.
};
inline bool operator==(const Use& lhs, const Use& rhs) {
return lhs.inst == rhs.inst && lhs.operand_index == rhs.operand_index;
}
inline bool operator!=(const Use& lhs, const Use& rhs) { return !(lhs == rhs); }
inline bool operator<(const Use& lhs, const Use& rhs) {
if (lhs.inst < rhs.inst) return true;
if (lhs.inst > rhs.inst) return false;
return lhs.operand_index < rhs.operand_index;
}
// Definition should never be null. User can be null, however, such an entry
// should be used only for searching (e.g. all users of a particular definition)
// and never stored in a container.

View File

@ -54,9 +54,10 @@ Pass::Status DescriptorScalarReplacement::Process() {
bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
std::vector<Instruction*> access_chain_work_list;
std::vector<Instruction*> load_work_list;
std::vector<Instruction*> entry_point_work_list;
bool failed = !get_def_use_mgr()->WhileEachUser(
var->result_id(),
[this, &access_chain_work_list, &load_work_list](Instruction* use) {
var->result_id(), [this, &access_chain_work_list, &load_work_list,
&entry_point_work_list](Instruction* use) {
if (use->opcode() == spv::Op::OpName) {
return true;
}
@ -73,6 +74,9 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
case spv::Op::OpLoad:
load_work_list.push_back(use);
return true;
case spv::Op::OpEntryPoint:
entry_point_work_list.push_back(use);
return true;
default:
context()->EmitErrorMessage(
"Variable cannot be replaced: invalid instruction", use);
@ -95,6 +99,11 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
return false;
}
}
for (Instruction* use : entry_point_work_list) {
if (!ReplaceEntryPoint(var, use)) {
return false;
}
}
return true;
}
@ -147,6 +156,42 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var,
return true;
}
bool DescriptorScalarReplacement::ReplaceEntryPoint(Instruction* var,
Instruction* use) {
// Build a new |OperandList| for |use| that removes |var| and adds its
// replacement variables.
Instruction::OperandList new_operands;
// Copy all operands except |var|.
bool found = false;
for (uint32_t idx = 0; idx < use->NumOperands(); idx++) {
Operand& op = use->GetOperand(idx);
if (op.type == SPV_OPERAND_TYPE_ID && op.words[0] == var->result_id()) {
found = true;
} else {
new_operands.emplace_back(op);
}
}
if (!found) {
context()->EmitErrorMessage(
"Variable cannot be replaced: invalid instruction", use);
return false;
}
// Add all new replacement variables.
uint32_t num_replacement_vars =
descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var);
for (uint32_t i = 0; i < num_replacement_vars; i++) {
new_operands.push_back(
{SPV_OPERAND_TYPE_ID, {GetReplacementVariable(var, i)}});
}
use->ReplaceOperands(new_operands);
context()->UpdateDefUse(use);
return true;
}
uint32_t DescriptorScalarReplacement::GetReplacementVariable(Instruction* var,
uint32_t idx) {
auto replacement_vars = replacement_variables_.find(var);

View File

@ -64,6 +64,11 @@ class DescriptorScalarReplacement : public Pass {
// otherwise.
bool ReplaceLoadedValue(Instruction* var, Instruction* value);
// Replaces the given composite variable |var| in the OpEntryPoint with the
// new replacement variables, one for each element of the array |var|. Returns
// |true| if successful, and |false| otherwise.
bool ReplaceEntryPoint(Instruction* var, Instruction* use);
// Replaces the given OpCompositeExtract |extract| and all of its references
// with an OpLoad of a replacement variable. |var| is the variable with
// composite type whose value is being used by |extract|. Assumes that

View File

@ -229,6 +229,8 @@ class IRContext {
inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
// Set the memory model for this module.
inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
// Get the memory model for this module.
inline const Instruction* GetMemoryModel() const;
// Appends an entry point instruction to this module.
inline void AddEntryPoint(std::unique_ptr<Instruction>&& e);
// Appends an execution mode instruction to this module.
@ -1156,6 +1158,10 @@ void IRContext::SetMemoryModel(std::unique_ptr<Instruction>&& m) {
module()->SetMemoryModel(std::move(m));
}
const Instruction* IRContext::GetMemoryModel() const {
return module()->GetMemoryModel();
}
void IRContext::AddEntryPoint(std::unique_ptr<Instruction>&& e) {
module()->AddEntryPoint(std::move(e));
}

View File

@ -420,8 +420,8 @@ void LocalAccessChainConvertPass::InitExtensions() {
"SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing",
"SPV_NV_fragment_shader_barycentric",
"SPV_NV_compute_shader_derivatives", "SPV_NV_shader_image_footprint",
"SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing",
"SPV_KHR_ray_tracing", "SPV_KHR_ray_query",
"SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_EXT_mesh_shader",
"SPV_NV_ray_tracing", "SPV_KHR_ray_tracing", "SPV_KHR_ray_query",
"SPV_EXT_fragment_invocation_density", "SPV_KHR_terminate_invocation",
"SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product",
"SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info",

View File

@ -273,6 +273,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
"SPV_NV_shader_image_footprint",
"SPV_NV_shading_rate",
"SPV_NV_mesh_shader",
"SPV_EXT_mesh_shader",
"SPV_NV_ray_tracing",
"SPV_KHR_ray_tracing",
"SPV_KHR_ray_query",

View File

@ -124,6 +124,7 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() {
"SPV_NV_shader_image_footprint",
"SPV_NV_shading_rate",
"SPV_NV_mesh_shader",
"SPV_EXT_mesh_shader",
"SPV_NV_ray_tracing",
"SPV_KHR_ray_query",
"SPV_EXT_fragment_invocation_density",

View File

@ -0,0 +1,103 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "modify_maximal_reconvergence.h"
#include "source/opt/ir_context.h"
#include "source/util/make_unique.h"
namespace spvtools {
namespace opt {
Pass::Status ModifyMaximalReconvergence::Process() {
bool changed = false;
if (add_) {
changed = AddMaximalReconvergence();
} else {
changed = RemoveMaximalReconvergence();
}
return changed ? Pass::Status::SuccessWithChange
: Pass::Status::SuccessWithoutChange;
}
bool ModifyMaximalReconvergence::AddMaximalReconvergence() {
bool changed = false;
bool has_extension = false;
bool has_shader =
context()->get_feature_mgr()->HasCapability(spv::Capability::Shader);
for (auto extension : context()->extensions()) {
if (extension.GetOperand(0).AsString() == "SPV_KHR_maximal_reconvergence") {
has_extension = true;
break;
}
}
std::unordered_set<uint32_t> entry_points_with_mode;
for (auto mode : get_module()->execution_modes()) {
if (spv::ExecutionMode(mode.GetSingleWordInOperand(1)) ==
spv::ExecutionMode::MaximallyReconvergesKHR) {
entry_points_with_mode.insert(mode.GetSingleWordInOperand(0));
}
}
for (auto entry_point : get_module()->entry_points()) {
const uint32_t id = entry_point.GetSingleWordInOperand(1);
if (!entry_points_with_mode.count(id)) {
changed = true;
if (!has_extension) {
context()->AddExtension("SPV_KHR_maximal_reconvergence");
has_extension = true;
}
if (!has_shader) {
context()->AddCapability(spv::Capability::Shader);
has_shader = true;
}
context()->AddExecutionMode(MakeUnique<Instruction>(
context(), spv::Op::OpExecutionMode, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {id}},
{SPV_OPERAND_TYPE_EXECUTION_MODE,
{static_cast<uint32_t>(
spv::ExecutionMode::MaximallyReconvergesKHR)}}}));
entry_points_with_mode.insert(id);
}
}
return changed;
}
bool ModifyMaximalReconvergence::RemoveMaximalReconvergence() {
bool changed = false;
std::vector<Instruction*> to_remove;
Instruction* mode = &*get_module()->execution_mode_begin();
while (mode) {
if (mode->opcode() != spv::Op::OpExecutionMode &&
mode->opcode() != spv::Op::OpExecutionModeId) {
break;
}
if (spv::ExecutionMode(mode->GetSingleWordInOperand(1)) ==
spv::ExecutionMode::MaximallyReconvergesKHR) {
mode = context()->KillInst(mode);
changed = true;
} else {
mode = mode->NextNode();
}
}
changed |=
context()->RemoveExtension(Extension::kSPV_KHR_maximal_reconvergence);
return changed;
}
} // namespace opt
} // namespace spvtools

View File

@ -0,0 +1,53 @@
// Copyright (c) 2024 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 LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
#define LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
#include "pass.h"
namespace spvtools {
namespace opt {
// Modifies entry points to either add or remove MaximallyReconvergesKHR
//
// This pass will either add or remove MaximallyReconvergesKHR to all entry
// points in the module. When adding the execution mode, it does not attempt to
// determine whether any ray tracing invocation repack instructions might be
// executed because it is a runtime restriction. That is left to the user.
class ModifyMaximalReconvergence : public Pass {
public:
const char* name() const override { return "modify-maximal-reconvergence"; }
Status Process() override;
explicit ModifyMaximalReconvergence(bool add = true) : Pass(), add_(add) {}
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
IRContext::kAnalysisCFG | IRContext::kAnalysisNameMap |
IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
}
private:
bool AddMaximalReconvergence();
bool RemoveMaximalReconvergence();
bool add_;
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_

View File

@ -606,6 +606,25 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag,
return false;
}
RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set));
} else if (pass_name == "modify-maximal-reconvergence") {
if (pass_args.size() == 0) {
Error(consumer(), nullptr, {},
"--modify-maximal-reconvergence requires an argument");
return false;
}
if (pass_args == "add") {
RegisterPass(CreateModifyMaximalReconvergencePass(true));
} else if (pass_args == "remove") {
RegisterPass(CreateModifyMaximalReconvergencePass(false));
} else {
Errorf(consumer(), nullptr, {},
"Invalid argument for --modify-maximal-reconvergence: %s (must be "
"'add' or 'remove')",
pass_args.c_str());
return false;
}
} else if (pass_name == "trim-capabilities") {
RegisterPass(CreateTrimCapabilitiesPass());
} else {
Errorf(consumer(), nullptr, {},
"Unknown flag '--%s'. Use --help for a list of valid flags",
@ -1141,6 +1160,11 @@ Optimizer::PassToken CreateInvocationInterlockPlacementPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::InvocationInterlockPlacementPass>());
}
Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::ModifyMaximalReconvergence>(add));
}
} // namespace spvtools
extern "C" {

View File

@ -65,6 +65,7 @@
#include "source/opt/loop_unroller.h"
#include "source/opt/loop_unswitch_pass.h"
#include "source/opt/merge_return_pass.h"
#include "source/opt/modify_maximal_reconvergence.h"
#include "source/opt/null_pass.h"
#include "source/opt/private_to_local_pass.h"
#include "source/opt/reduce_load_size.h"

View File

@ -448,6 +448,17 @@ void TrimCapabilitiesPass::addInstructionRequirementsForOperand(
return;
}
// If the Vulkan memory model is declared and any instruction uses Device
// scope, the VulkanMemoryModelDeviceScope capability must be declared. This
// rule cannot be covered by the grammar, so must be checked explicitly.
if (operand.type == SPV_OPERAND_TYPE_SCOPE_ID) {
const Instruction* memory_model = context()->GetMemoryModel();
if (memory_model && memory_model->GetSingleWordInOperand(1u) ==
uint32_t(spv::MemoryModel::Vulkan)) {
capabilities->insert(spv::Capability::VulkanMemoryModelDeviceScope);
}
}
// case 1: Operand is a single value, can directly lookup.
if (!spvOperandIsConcreteMask(operand.type)) {
const spv_operand_desc_t* desc = {};

View File

@ -97,7 +97,8 @@ class TrimCapabilitiesPass : public Pass {
spv::Capability::StorageInputOutput16,
spv::Capability::StoragePushConstant16,
spv::Capability::StorageUniform16,
spv::Capability::StorageUniformBufferBlock16
spv::Capability::StorageUniformBufferBlock16,
spv::Capability::VulkanMemoryModelDeviceScope
// clang-format on
};

View File

@ -141,6 +141,10 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
}
}
if (auto error = ValidateFloatControls2(_)) {
return error;
}
return SPV_SUCCESS;
}

View File

@ -82,6 +82,18 @@ spv_result_t ValidateAdjacency(ValidationState_t& _);
/// @return SPV_SUCCESS if no errors are found.
spv_result_t ValidateInterfaces(ValidationState_t& _);
/// @brief Validates entry point call tree requirements of
/// SPV_KHR_float_controls2
///
/// Checks that no entry point using FPFastMathDefault uses:
/// * FPFastMathMode Fast
/// * NoContraction
///
/// @param[in] _ the validation state of the module
///
/// @return SPV_SUCCESS if no errors are found.
spv_result_t ValidateFloatControls2(ValidationState_t& _);
/// @brief Validates memory instructions
///
/// @param[in] _ the validation state of the module

View File

@ -267,6 +267,34 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
}
}
if (decoration == spv::Decoration::FPFastMathMode) {
if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "FPFastMathMode and NoContraction cannot decorate the same "
"target";
}
auto mask = inst->GetOperandAs<spv::FPFastMathModeMask>(2);
if ((mask & spv::FPFastMathModeMask::AllowTransform) !=
spv::FPFastMathModeMask::MaskNone &&
((mask & (spv::FPFastMathModeMask::AllowContract |
spv::FPFastMathModeMask::AllowReassoc)) !=
(spv::FPFastMathModeMask::AllowContract |
spv::FPFastMathModeMask::AllowReassoc))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "AllowReassoc and AllowContract must be specified when "
"AllowTransform is specified";
}
}
// This is checked from both sides since we register decorations as we go.
if (decoration == spv::Decoration::NoContraction) {
if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "FPFastMathMode and NoContraction cannot decorate the same "
"target";
}
}
if (DecorationTakesIdParameters(decoration)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Decorations taking ID parameters may not be used with "

View File

@ -118,13 +118,15 @@ typedef enum VUIDError_ {
VUIDErrorMax,
} VUIDError;
const static uint32_t NumVUIDBuiltins = 36;
const static uint32_t NumVUIDBuiltins = 39;
typedef struct {
spv::BuiltIn builtIn;
uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
} BuiltinVUIDMapping;
// Many built-ins have the same checks (Storage Class, Type, etc)
// This table provides a nice LUT for the VUIDs
std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
// clang-format off
{spv::BuiltIn::SubgroupEqMask, {0, 4370, 4371}},
@ -163,8 +165,11 @@ std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
{spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}},
{spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}},
{spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}},
// clang-format off
} };
{spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}},
{spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}},
{spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
// clang-format on
}};
uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
uint32_t vuid = 0;
@ -356,6 +361,9 @@ class BuiltInsValidator {
spv_result_t ValidateRayTracingBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst);
spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst);
// The following section contains functions which are called when id defined
// by |referenced_inst| is
// 1. referenced by |referenced_from_inst|
@ -546,6 +554,11 @@ class BuiltInsValidator {
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidateMeshShadingEXTBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
// Validates that |built_in_inst| is not (even indirectly) referenced from
// within a function which can be called with |execution_model|.
//
@ -581,6 +594,10 @@ class BuiltInsValidator {
spv_result_t ValidateI32Arr(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateArrayedI32Vec(
const Decoration& decoration, const Instruction& inst,
uint32_t num_components,
const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateOptionalArrayedI32(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
@ -909,6 +926,45 @@ spv_result_t BuiltInsValidator::ValidateI32Vec(
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateArrayedI32Vec(
const Decoration& decoration, const Instruction& inst,
uint32_t num_components,
const std::function<spv_result_t(const std::string& message)>& diag) {
uint32_t underlying_type = 0;
if (spv_result_t error =
GetUnderlyingType(_, decoration, inst, &underlying_type)) {
return error;
}
const Instruction* const type_inst = _.FindDef(underlying_type);
if (type_inst->opcode() != spv::Op::OpTypeArray) {
return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
}
const uint32_t component_type = type_inst->word(2);
if (!_.IsIntVectorType(component_type)) {
return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
}
const uint32_t actual_num_components = _.GetDimension(component_type);
if (_.GetDimension(component_type) != num_components) {
std::ostringstream ss;
ss << GetDefinitionDesc(decoration, inst) << " has "
<< actual_num_components << " components.";
return diag(ss.str());
}
const uint32_t bit_width = _.GetBitWidth(component_type);
if (bit_width != 32) {
std::ostringstream ss;
ss << GetDefinitionDesc(decoration, inst)
<< " has components with bit width " << bit_width << ".";
return diag(ss.str());
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
const Decoration& decoration, const Instruction& inst,
uint32_t num_components,
@ -4108,6 +4164,119 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) {
if (spv_result_t error = ValidateI32Arr(
decoration, inst,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
<< " variable needs to be a 32-bit int array."
<< message;
})) {
return error;
}
}
if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) {
if (spv_result_t error = ValidateArrayedI32Vec(
decoration, inst, 2,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
<< " variable needs to be a 2-component 32-bit int "
"array."
<< message;
})) {
return error;
}
}
if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) {
if (spv_result_t error = ValidateArrayedI32Vec(
decoration, inst, 3,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
<< " variable needs to be a 3-component 32-bit int "
"array."
<< message;
})) {
return error;
}
}
}
// Seed at reference checks with this built-in.
return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst,
inst);
}
spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
const spv::StorageClass storage_class =
GetStorageClass(referenced_from_inst);
if (storage_class != spv::StorageClass::Max &&
storage_class != spv::StorageClass::Output) {
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
uint32_t(builtin))
<< " to be only used for variables with Output storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
<< " " << GetStorageClassDesc(referenced_from_inst);
}
for (const spv::ExecutionModel execution_model : execution_models_) {
if (execution_model != spv::ExecutionModel::MeshEXT) {
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(vuid)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
uint32_t(builtin))
<< " to be used only with MeshEXT 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(
std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference,
this, decoration, built_in_inst, referenced_from_inst,
std::placeholders::_1));
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
const Decoration& decoration, const Instruction& inst) {
const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
@ -4283,6 +4452,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case spv::BuiltIn::CullMaskKHR: {
return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
}
case spv::BuiltIn::PrimitivePointIndicesEXT:
case spv::BuiltIn::PrimitiveLineIndicesEXT:
case spv::BuiltIn::PrimitiveTriangleIndicesEXT: {
return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
}
case spv::BuiltIn::PrimitiveShadingRateKHR: {
return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
}

View File

@ -190,6 +190,8 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _,
"ID of an OpLabel instruction";
}
// A similar requirement for SPV_KHR_maximal_reconvergence is deferred until
// entry point call trees have been reconrded.
if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 6) && true_id == false_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "In SPIR-V 1.6 or later, True Label and False Label must be "
@ -875,6 +877,95 @@ spv_result_t StructuredControlFlowChecks(
return SPV_SUCCESS;
}
spv_result_t MaximalReconvergenceChecks(ValidationState_t& _) {
// Find all the entry points with the MaximallyReconvergencesKHR execution
// mode.
std::unordered_set<uint32_t> maximal_funcs;
std::unordered_set<uint32_t> maximal_entry_points;
for (auto entry_point : _.entry_points()) {
const auto* exec_modes = _.GetExecutionModes(entry_point);
if (exec_modes &&
exec_modes->count(spv::ExecutionMode::MaximallyReconvergesKHR)) {
maximal_entry_points.insert(entry_point);
maximal_funcs.insert(entry_point);
}
}
if (maximal_entry_points.empty()) {
return SPV_SUCCESS;
}
// Find all the functions reachable from a maximal reconvergence entry point.
for (const auto& func : _.functions()) {
const auto& entry_points = _.EntryPointReferences(func.id());
for (auto id : entry_points) {
if (maximal_entry_points.count(id)) {
maximal_funcs.insert(func.id());
break;
}
}
}
// Check for conditional branches with the same true and false targets.
for (const auto& inst : _.ordered_instructions()) {
if (inst.opcode() == spv::Op::OpBranchConditional) {
const auto true_id = inst.GetOperandAs<uint32_t>(1);
const auto false_id = inst.GetOperandAs<uint32_t>(2);
if (true_id == false_id && maximal_funcs.count(inst.function()->id())) {
return _.diag(SPV_ERROR_INVALID_ID, &inst)
<< "In entry points using the MaximallyReconvergesKHR execution "
"mode, True Label and False Label must be different labels";
}
}
}
// Check for invalid multiple predecessors. Only loop headers, continue
// targets, merge targets or switch targets or defaults may have multiple
// unique predecessors.
for (const auto& func : _.functions()) {
if (!maximal_funcs.count(func.id())) continue;
for (const auto* block : func.ordered_blocks()) {
std::unordered_set<uint32_t> unique_preds;
const auto* preds = block->predecessors();
if (!preds) continue;
for (const auto* pred : *preds) {
unique_preds.insert(pred->id());
}
if (unique_preds.size() < 2) continue;
const auto* terminator = block->terminator();
const auto index = terminator - &_.ordered_instructions()[0];
const auto* pre_terminator = &_.ordered_instructions()[index - 1];
if (pre_terminator->opcode() == spv::Op::OpLoopMerge) continue;
const auto* label = _.FindDef(block->id());
bool ok = false;
for (const auto& pair : label->uses()) {
const auto* use_inst = pair.first;
switch (use_inst->opcode()) {
case spv::Op::OpSelectionMerge:
case spv::Op::OpLoopMerge:
case spv::Op::OpSwitch:
ok = true;
break;
default:
break;
}
}
if (!ok) {
return _.diag(SPV_ERROR_INVALID_CFG, label)
<< "In entry points using the MaximallyReconvergesKHR "
"execution mode, this basic block must not have multiple "
"unique predecessors";
}
}
}
return SPV_SUCCESS;
}
spv_result_t PerformCfgChecks(ValidationState_t& _) {
for (auto& function : _.functions()) {
// Check all referenced blocks are defined within a function
@ -999,6 +1090,11 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) {
return error;
}
}
if (auto error = MaximalReconvergenceChecks(_)) {
return error;
}
return SPV_SUCCESS;
}

View File

@ -470,7 +470,8 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) {
}
_.set_addressing_model(inst->GetOperandAs<spv::AddressingModel>(0));
_.set_memory_model(inst->GetOperandAs<spv::MemoryModel>(1));
} else if (opcode == spv::Op::OpExecutionMode) {
} else if (opcode == spv::Op::OpExecutionMode ||
opcode == spv::Op::OpExecutionModeId) {
const uint32_t entry_point = inst->word(1);
_.RegisterExecutionModeForEntryPoint(entry_point,
spv::ExecutionMode(inst->word(2)));

View File

@ -203,15 +203,12 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
"storage class";
}
#if 0
// TODO(atgoo@github.com): this check fails Vulkan CTS, reenable once fixed.
if (opcode == spv::Op::OpControlBarrier && value && !includes_storage_class) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< spvOpcodeString(opcode)
<< _.VkErrorID(4650) << spvOpcodeString(opcode)
<< ": expected Memory Semantics to include a Vulkan-supported "
"storage class if Memory Semantics is not None";
}
#endif
}
if (opcode == spv::Op::OpAtomicFlagClear &&

View File

@ -340,29 +340,92 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
const auto mode = inst->GetOperandAs<spv::ExecutionMode>(1);
if (inst->opcode() == spv::Op::OpExecutionModeId) {
bool valid_mode = false;
switch (mode) {
case spv::ExecutionMode::SubgroupsPerWorkgroupId:
case spv::ExecutionMode::LocalSizeHintId:
case spv::ExecutionMode::LocalSizeId:
case spv::ExecutionMode::FPFastMathDefault:
valid_mode = true;
break;
default:
valid_mode = false;
break;
}
if (!valid_mode) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpExecutionModeId is only valid when the Mode operand is an "
"execution mode that takes Extra Operands that are id "
"operands.";
}
size_t operand_count = inst->operands().size();
for (size_t i = 2; i < operand_count; ++i) {
const auto operand_id = inst->GetOperandAs<uint32_t>(2);
const auto operand_id = inst->GetOperandAs<uint32_t>(i);
const auto* operand_inst = _.FindDef(operand_id);
if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
mode == spv::ExecutionMode::LocalSizeHintId ||
mode == spv::ExecutionMode::LocalSizeId) {
if (!spvOpcodeIsConstant(operand_inst->opcode())) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "For OpExecutionModeId all Extra Operand ids must be "
"constant "
"instructions.";
}
} else {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpExecutionModeId is only valid when the Mode operand is an "
"execution mode that takes Extra Operands that are id "
"operands.";
switch (mode) {
case spv::ExecutionMode::SubgroupsPerWorkgroupId:
case spv::ExecutionMode::LocalSizeHintId:
case spv::ExecutionMode::LocalSizeId:
if (!spvOpcodeIsConstant(operand_inst->opcode())) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "For OpExecutionModeId all Extra Operand ids must be "
"constant instructions.";
}
break;
case spv::ExecutionMode::FPFastMathDefault:
if (i == 2) {
if (!_.IsFloatScalarType(operand_id)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "The Target Type operand must be a floating-point "
"scalar type";
}
} else {
bool is_int32 = false;
bool is_const = false;
uint32_t value = 0;
std::tie(is_int32, is_const, value) =
_.EvalInt32IfConst(operand_id);
if (is_int32 && is_const) {
// Valid values include up to 0x00040000 (AllowTransform).
uint32_t invalid_mask = 0xfff80000;
if ((invalid_mask & value) != 0) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "The Fast Math Default operand is an invalid bitmask "
"value";
}
if (value &
static_cast<uint32_t>(spv::FPFastMathModeMask::Fast)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "The Fast Math Default operand must not include Fast";
}
const auto reassoc_contract =
spv::FPFastMathModeMask::AllowContract |
spv::FPFastMathModeMask::AllowReassoc;
if ((value & static_cast<uint32_t>(
spv::FPFastMathModeMask::AllowTransform)) != 0 &&
((value & static_cast<uint32_t>(reassoc_contract)) !=
static_cast<uint32_t>(reassoc_contract))) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "The Fast Math Default operand must include "
"AllowContract and AllowReassoc when AllowTransform "
"is specified";
}
} else {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "The Fast Math Default operand must be a "
"non-specialization constant";
}
}
break;
default:
break;
}
}
} else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
mode == spv::ExecutionMode::LocalSizeHintId ||
mode == spv::ExecutionMode::LocalSizeId) {
mode == spv::ExecutionMode::LocalSizeId ||
mode == spv::ExecutionMode::FPFastMathDefault) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "OpExecutionMode is only valid when the Mode operand is an "
"execution mode that takes no Extra Operands, or takes Extra "
@ -494,6 +557,17 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
"model.";
}
break;
case spv::ExecutionMode::QuadDerivativesKHR:
if (!std::all_of(models->begin(), models->end(),
[](const spv::ExecutionModel& model) {
return (model == spv::ExecutionModel::Fragment ||
model == spv::ExecutionModel::GLCompute);
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Fragment or "
"GLCompute execution model.";
}
break;
case spv::ExecutionMode::PixelCenterInteger:
case spv::ExecutionMode::OriginUpperLeft:
case spv::ExecutionMode::OriginLowerLeft:
@ -518,6 +592,7 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
case spv::ExecutionMode::StencilRefUnchangedBackAMD:
case spv::ExecutionMode::StencilRefGreaterBackAMD:
case spv::ExecutionMode::StencilRefLessBackAMD:
case spv::ExecutionMode::RequireFullQuadsKHR:
if (!std::all_of(models->begin(), models->end(),
[](const spv::ExecutionModel& model) {
return model == spv::ExecutionModel::Fragment;
@ -579,6 +654,20 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
break;
}
if (mode == spv::ExecutionMode::FPFastMathDefault) {
const auto* modes = _.GetExecutionModes(entry_point_id);
if (modes && modes->count(spv::ExecutionMode::ContractionOff)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "FPFastMathDefault and ContractionOff execution modes cannot "
"be applied to the same entry point";
}
if (modes && modes->count(spv::ExecutionMode::SignedZeroInfNanPreserve)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "FPFastMathDefault and SignedZeroInfNanPreserve execution "
"modes cannot be applied to the same entry point";
}
}
if (spvIsVulkanEnv(_.context()->target_env)) {
if (mode == spv::ExecutionMode::OriginLowerLeft) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@ -636,6 +725,70 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _,
} // namespace
spv_result_t ValidateFloatControls2(ValidationState_t& _) {
std::unordered_set<uint32_t> fp_fast_math_default_entry_points;
for (auto entry_point : _.entry_points()) {
const auto* exec_modes = _.GetExecutionModes(entry_point);
if (exec_modes &&
exec_modes->count(spv::ExecutionMode::FPFastMathDefault)) {
fp_fast_math_default_entry_points.insert(entry_point);
}
}
std::vector<std::pair<const Instruction*, spv::Decoration>> worklist;
for (const auto& inst : _.ordered_instructions()) {
if (inst.opcode() != spv::Op::OpDecorate) {
continue;
}
const auto decoration = inst.GetOperandAs<spv::Decoration>(1);
const auto target_id = inst.GetOperandAs<uint32_t>(0);
const auto target = _.FindDef(target_id);
if (decoration == spv::Decoration::NoContraction) {
worklist.push_back(std::make_pair(target, decoration));
} else if (decoration == spv::Decoration::FPFastMathMode) {
auto mask = inst.GetOperandAs<spv::FPFastMathModeMask>(2);
if ((mask & spv::FPFastMathModeMask::Fast) !=
spv::FPFastMathModeMask::MaskNone) {
worklist.push_back(std::make_pair(target, decoration));
}
}
}
std::unordered_set<const Instruction*> visited;
while (!worklist.empty()) {
const auto inst = worklist.back().first;
const auto decoration = worklist.back().second;
worklist.pop_back();
if (!visited.insert(inst).second) {
continue;
}
const auto function = inst->function();
if (function) {
const auto& entry_points = _.FunctionEntryPoints(function->id());
for (auto entry_point : entry_points) {
if (fp_fast_math_default_entry_points.count(entry_point)) {
const std::string dec = decoration == spv::Decoration::NoContraction
? "NoContraction"
: "FPFastMathMode Fast";
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< dec
<< " cannot be used by an entry point with the "
"FPFastMathDefault execution mode";
}
}
} else {
for (const auto& pair : inst->uses()) {
worklist.push_back(std::make_pair(pair.first, decoration));
}
}
}
return SPV_SUCCESS;
}
spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
switch (inst->opcode()) {
case spv::Op::OpEntryPoint:

View File

@ -422,9 +422,14 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) {
const spv::Op opcode = inst->opcode();
if (spvOpcodeIsNonUniformGroupOperation(opcode)) {
const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
return error;
// OpGroupNonUniformQuadAllKHR and OpGroupNonUniformQuadAnyKHR don't have
// scope paramter
if ((opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
(opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) {
const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
return error;
}
}
}

View File

@ -97,8 +97,10 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
// Vulkan 1.1 specific rules
if (_.context()->target_env != SPV_ENV_VULKAN_1_0) {
// Scope for Non Uniform Group Operations must be limited to Subgroup
if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
value != spv::Scope::Subgroup) {
if ((spvOpcodeIsNonUniformGroupOperation(opcode) &&
(opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
(opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) &&
(value != spv::Scope::Subgroup)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4642) << spvOpcodeString(opcode)
<< ": in Vulkan environment Execution scope is limited to "
@ -178,6 +180,8 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
// Scope for execution must be limited to Workgroup or Subgroup for
// non-uniform operations
if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
opcode != spv::Op::OpGroupNonUniformQuadAllKHR &&
opcode != spv::Op::OpGroupNonUniformQuadAnyKHR &&
value != spv::Scope::Subgroup && value != spv::Scope::Workgroup) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< spvOpcodeString(opcode)

View File

@ -2125,6 +2125,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-None-04644);
case 4645:
return VUID_WRAP(VUID-StandaloneSpirv-None-04645);
case 4650:
return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04650);
case 4651:
return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
case 4652:
@ -2257,6 +2259,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808);
case 6925:
return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
case 7041:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041);
case 7043:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043);
case 7044:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044);
case 7047:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047);
case 7049:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049);
case 7050:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050);
case 7053:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053);
case 7055:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055);
case 7056:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056);
case 7102:
return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
case 7320: