mirror of https://github.com/bkaradzic/bgfx
Updated spirv-tools.
This commit is contained in:
parent
56f7af3103
commit
3ac2dda244
|
@ -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"),
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -1 +1 @@
|
|||
"v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-7-g57aba7ff"
|
||||
"v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-37-g58b2f0b6"
|
||||
|
|
|
@ -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
|
@ -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,
|
||||
|
|
|
@ -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"},
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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" {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -141,6 +141,10 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
|||
}
|
||||
}
|
||||
|
||||
if (auto error = ValidateFloatControls2(_)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue